Interceptors Hibernasi

1. Ikhtisar

Dalam diskusi ini, kita akan melihat berbagai cara untuk mencegat operasi dalam implementasi pemetaan relasional abstrak Hibernate.

2. Mendefinisikan Interceptors Hibernate

Hibernate Interceptor adalah antarmuka yang memungkinkan kita bereaksi terhadap peristiwa tertentu dalam Hibernate.

Pencegat ini terdaftar sebagai callback dan menyediakan tautan komunikasi antara sesi dan aplikasi Hibernate. Dengan panggilan balik seperti itu, aplikasi dapat menghalangi operasi inti Hibernate seperti menyimpan, memperbarui, menghapus, dll.

Ada dua cara untuk mendefinisikan interseptor:

  1. mengimplementasikan antarmuka org.hibernate.Interceptor
  2. memperluas kelas org.hibernate.EmptyInterceptor

2.1. Menerapkan Antarmuka Interceptor

Menerapkan org.hibernate.Interceptor membutuhkan penerapan sekitar 14 metode yang menyertai . Metode ini termasuk onLoad, onSave, onDelete, findDirty, dan beberapa lainnya.

Penting juga untuk memastikan bahwa setiap kelas yang mengimplementasikan antarmuka Interceptor dapat bersambung ( mengimplementasikan java.io.Serializable ).

Contoh tipikal akan terlihat seperti:

public class CustomInterceptorImpl implements Interceptor, Serializable { @Override public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException { // ... return false; } // ... @Override public String onPrepareStatement(String sql) { // ... return sql; } }

Jika tidak ada persyaratan khusus, sangat disarankan untuk memperluas kelas EmptyInterceptor dan hanya mengganti metode yang diperlukan.

2.2. Memperluas EmptyInterceptor

Memperluas kelas org.hibernate.EmptyInterceptor memberikan cara yang lebih mudah untuk mendefinisikan pencegat. Sekarang kita hanya perlu mengganti metode yang berhubungan dengan operasi yang ingin kita intersep.

Misalnya, kita dapat mendefinisikan CustomInterceptor kita sebagai:

public class CustomInterceptor extends EmptyInterceptor { }

Dan jika kita perlu mencegat operasi penyimpanan data sebelum dijalankan, kita perlu mengganti metode onSave :

@Override public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { if (entity instanceof User) { logger.info(((User) entity).toString()); } return super.onSave(entity, id, state, propertyNames, types); }

Perhatikan bagaimana implementasi ini hanya mencetak entitas - jika itu adalah Pengguna .

Meskipun mungkin untuk mengembalikan nilai benar atau salah , itu adalah praktik yang baik untuk mengizinkan penyebaran peristiwa onSave dengan memanggil super.onSave () .

Kasus penggunaan lain akan menyediakan jejak audit untuk interaksi database. Kita bisa menggunakan metode onFlushDirty () untuk mengetahui kapan entitas berubah.

Untuk objek User , kita dapat memutuskan untuk mengupdate properti lastModified date setiap kali terjadi perubahan pada entitas bertipe User .

Ini dapat dicapai dengan:

@Override public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object [] previousState, String[] propertyNames, Type[] types) { if (entity instanceof User) { ((User) entity).setLastModified(new Date()); logger.info(((User) entity).toString()); } return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types); }

Peristiwa lain seperti delete dan load (inisialisasi objek) dapat dicegat dengan mengimplementasikan metode onDelete dan onLoad yang sesuai .

3. Mendaftarkan Interceptors

Sebuah pencegat Hibernate dapat didaftarkan sebagai Session -scoped atau SessionFactory-scoped .

3.1. Interceptor dengan cakupan sesi

Sebuah pencegat cakupan sesi ditautkan ke sesi tertentu. Itu dibuat ketika sesi didefinisikan atau dibuka sebagai:

public static Session getSessionWithInterceptor(Interceptor interceptor) throws IOException { return getSessionFactory().withOptions() .interceptor(interceptor).openSession(); }

Di atas, kami secara eksplisit mendaftarkan pencegat dengan sesi hibernasi tertentu.

3.2. SessionFactory -scoped Interceptor

Sebuah interseptor dengan cakupan SessionFactory didaftarkan sebelum membangun SessionFactory. Ini biasanya dilakukan melalui metode applyInterceptor pada instance SessionFactoryBuilder :

ServiceRegistry serviceRegistry = configureServiceRegistry(); SessionFactory sessionFactory = getSessionFactoryBuilder(serviceRegistry) .applyInterceptor(new CustomInterceptor()) .build();

Penting untuk dicatat bahwa interseptor dengan cakupan SessionFactory akan diterapkan ke semua sesi. Oleh karena itu, kita perlu berhati-hati untuk tidak menyimpan status khusus sesi - karena pencegat ini akan digunakan oleh sesi yang berbeda secara bersamaan.

Untuk perilaku khusus sesi, disarankan untuk secara eksplisit membuka sesi dengan interseptor berbeda seperti yang ditunjukkan sebelumnya.

Untuk interseptor dengan cakupan SessionFactory , kami secara alami perlu memastikan bahwa itu thread-safe. Ini dapat dicapai dengan menentukan konteks sesi di file properti:

hibernate.current_session_context_class=org.hibernate.context.internal.ThreadLocalSessionContext

Atau dengan menambahkan ini ke file konfigurasi XML kami:

 org.hibernate.context.internal.ThreadLocalSessionContext 

Selain itu, untuk memastikan kemampuan serial, interseptor dengan cakupan SessionFactory harus mengimplementasikan metode readResolve dari antarmuka Serializable .

4. Kesimpulan

Kami telah melihat bagaimana mendefinisikan dan mendaftarkan interseptor Hibernate baik sebagai Session -scoped atau SessionFactory -scoped. Dalam kedua kasus tersebut, kita harus memastikan bahwa interseptor dapat diserialkan terutama jika kita menginginkan sesi yang dapat serial.

Alternatif lain untuk interseptor termasuk Acara Hibernasi dan Panggilan Balik JPA.

Dan, seperti biasa, Anda dapat melihat kode sumber lengkapnya di Github.