1. 程式人生 > >Hibernate攔截器(Interceptor)與事件監聽器(Listener)

Hibernate攔截器(Interceptor)與事件監聽器(Listener)

前言:

由於專案中(S2SH框架)用到了memcache快取伺服器,考慮到同步問題是用每個bean變更時同時更新快取還是用類似資料庫trigger(觸發器)去實現呢,答案當然是用類似trigger的方式了,其優點不言而喻,畢竟這麼寫一勞永逸。

經調查發現,hibernate有兩種方式可以實現:

        攔截器(Intercept):與Struts2的攔截器機制基本一樣,都是一個操作穿過一層層攔截器,每穿過一個攔截器就會觸發相應攔截器的事件做預處理或善後處理。

  監聽器(Listener):其實功能與攔截器是相似的,但它實現原理不同,它是為每一個事件註冊一個或多個監聽器,一旦事件發生,則事件源通知所有監聽該事件的監聽器,然後監聽器處理通知(觀察者模式)。

攔截器具體實現:

[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. package fi.uum.cache.intercepter;  
  2. import java.io.Serializable;  
  3. import java.util.Iterator;  
  4. import org.hibernate.CallbackException;  
  5. import org.hibernate.EmptyInterceptor;  
  6. import org.hibernate.type.Type;  
  7. import org.springframework.stereotype.Component;  
  8. @Component
  9. publicclass CacheIntercepter extends EmptyInterceptor{  
  10.     /** 
  11.      *  
  12.      */
  13.     privatestaticfinallong serialVersionUID = 1L;  
  14.     @Override
  15.     publicvoid onDelete(Object entity, Serializable id, Object[] state,  
  16.             String[] propertyNames, Type[] types) {  
  17.         System.out.println("delete.............."
    );  
  18.         super.onDelete(entity, id, state, propertyNames, types);  
  19.     }  
  20.     @Override
  21.     publicboolean onFlushDirty(Object entity, Serializable id,  
  22.             Object[] currentState, Object[] previousState,  
  23.             String[] propertyNames, Type[] types) {  
  24.         System.out.println("flushDirty..............");  
  25.         returnsuper.onFlushDirty(entity, id, currentState, previousState,  
  26.                 propertyNames, types);  
  27.     }  
  28.     @Override
  29.     publicboolean onSave(Object entity, Serializable id, Object[] state,  
  30.             String[] propertyNames, Type[] types) {  
  31.         System.out.println("save..............");  
  32.         returnsuper.onSave(entity, id, state, propertyNames, types);  
  33.     }  
  34.     @Override
  35.     publicvoid onCollectionRecreate(Object collection, Serializable key)  
  36.             throws CallbackException {  
  37.         System.out.println("recreate..............");  
  38.         super.onCollectionRecreate(collection, key);  
  39.     }  
  40.     @Override
  41.     publicvoid onCollectionRemove(Object collection, Serializable key)  
  42.             throws CallbackException {  
  43.         System.out.println("remove..............");  
  44.         super.onCollectionRemove(collection, key);  
  45.     }  
  46.     @Override
  47.     publicvoid onCollectionUpdate(Object collection, Serializable key)  
  48.             throws CallbackException {  
  49.         System.out.println("collectionUpdate..............");  
  50.         super.onCollectionUpdate(collection, key);  
  51.     }  
  52.     @Override
  53.     publicboolean onLoad(Object entity, Serializable id, Object[] state,  
  54.             String[] propertyNames, Type[] types) {  
  55.         System.out.println("load..............");  
  56.         returnsuper.onLoad(entity, id, state, propertyNames, types);  
  57.     }  
  58.     @Override
  59.     publicvoid postFlush(Iterator entities) {  
  60.         System.out.println("flush..............");  
  61.         super.postFlush(entities);  
  62.     }  
  63.     @Override
  64.     public String onPrepareStatement(String sql) {  
  65.         System.out.println("statement.............."+sql);  
  66.         returnsuper.onPrepareStatement(sql);  
  67.     }  
  68.     @Override
  69.     publicvoid preFlush(Iterator entities) {  
  70.         System.out.println("preflush..............");  
  71.         super.preFlush(entities);  
  72.     }  
  73. }  

類繼承EmptyInterceptor是官方推薦做法。

PS:@Component為spring元件(bean)宣告方式,用法類似<bean id="" class=""> beanid 預設為類名(第一個字母小寫),使用@Component前需要先在srping配置檔案中宣告<!-- 配置注入資訊的包 --><context:component-scan base-package="*" /> 。
最後,Hibernate的攔截器有兩種設定方式,一種是使用sessionFactory.openSession(Interceptor interceptor),這樣的攔截器只會針對該session有效,又叫做區域性攔截器。另一種是使用Configuration的setInterceptor(Interceptor interceptor)方法設定,這樣的攔截器對每一個session都有效,又稱之為全域性攔截器,全域性攔截器還有種配置方法是在sessionFactory bean中加

[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. <property name="entityInterceptor">  
  2.             <ref bean="cacheIntercepter"/>  
  3.         </property>  


事件監聽器實現:

[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. package fi.uum.cache.listener;  
  2. import org.hibernate.event.spi.PostDeleteEvent;  
  3. import org.hibernate.event.spi.PostDeleteEventListener;  
  4. import org.hibernate.event.spi.PostInsertEvent;  
  5. import org.hibernate.event.spi.PostInsertEventListener;  
  6. import org.hibernate.event.spi.PostUpdateEvent;  
  7. import org.hibernate.event.spi.PostUpdateEventListener;  
  8. import org.hibernate.persister.entity.EntityPersister;  
  9. import org.springframework.stereotype.Component;  
  10. @Component
  11. publicclass CacheEventListener implements PostUpdateEventListener ,  
  12.     PostInsertEventListener,PostDeleteEventListener{  
  13.     /** 
  14.      *  
  15.      */
  16.     privatestaticfinallong serialVersionUID = 1L;  
  17.     @Override
  18.     publicvoid onPostDelete(PostDeleteEvent arg0) {  
  19.         System.out.println("delete...................");  
  20.     }  
  21.     @Override
  22.     publicvoid onPostInsert(PostInsertEvent arg0) {  
  23.         System.out.println("insert...................");  
  24.     }  
  25.     @Override
  26.     publicvoid onPostUpdate(PostUpdateEvent arg0) {  
  27.         System.out.println("update...................");  
  28.     }  
  29.     @Override
  30.     publicboolean requiresPostCommitHanding(EntityPersister arg0) {  
  31.         System.out.println("here...................");  
  32.         returnfalse;  
  33.     }  
  34. }  

配置方法:

在hibernate4中,檢視LocalSessionFactroyBean原始碼去不支援EventListener。spring3.X 對hibernate4不支援這樣的配置,hibernate4 改變了註冊EventListener的方式,這裡使用註解方式:

[java] view plaincopyprint?在CODE上檢視程式碼片派生到我的程式碼片
  1. package fi.uum.common.config;  
  2. import javax.annotation.PostConstruct;  
  3. import org.hibernate.SessionFactory;  
  4. import org.hibernate.event.service.spi.EventListenerRegistry;  
  5. import org.hibernate.event.spi.EventType;  
  6. import org.hibernate.internal.SessionFactoryImpl;  
  7. import org.springframework.bea