Hibernate攔截器(Interceptor)與事件監聽器(Listener)
前言:
由於專案中(S2SH框架)用到了memcache快取伺服器,考慮到同步問題是用每個bean變更時同時更新快取還是用類似資料庫trigger(觸發器)去實現呢,答案當然是用類似trigger的方式了,其優點不言而喻,畢竟這麼寫一勞永逸。
經調查發現,hibernate有兩種方式可以實現:
攔截器(Intercept):與Struts2的攔截器機制基本一樣,都是一個操作穿過一層層攔截器,每穿過一個攔截器就會觸發相應攔截器的事件做預處理或善後處理。
監聽器(Listener):其實功能與攔截器是相似的,但它實現原理不同,它是為每一個事件註冊一個或多個監聽器,一旦事件發生,則事件源通知所有監聽該事件的監聽器,然後監聽器處理通知(觀察者模式)。
攔截器具體實現:
[java] view plaincopyprint?- package fi.uum.cache.intercepter;
- import java.io.Serializable;
- import java.util.Iterator;
- import org.hibernate.CallbackException;
- import org.hibernate.EmptyInterceptor;
- import org.hibernate.type.Type;
-
import org.springframework.stereotype.Component;
- @Component
- publicclass CacheIntercepter extends EmptyInterceptor{
- /**
- *
- */
- privatestaticfinallong serialVersionUID = 1L;
- @Override
- publicvoid onDelete(Object entity, Serializable id, Object[] state,
- String[] propertyNames, Type[] types) {
-
System.out.println("delete.............."
- super.onDelete(entity, id, state, propertyNames, types);
- }
- @Override
- publicboolean onFlushDirty(Object entity, Serializable id,
- Object[] currentState, Object[] previousState,
- String[] propertyNames, Type[] types) {
- System.out.println("flushDirty..............");
- returnsuper.onFlushDirty(entity, id, currentState, previousState,
- propertyNames, types);
- }
- @Override
- publicboolean onSave(Object entity, Serializable id, Object[] state,
- String[] propertyNames, Type[] types) {
- System.out.println("save..............");
- returnsuper.onSave(entity, id, state, propertyNames, types);
- }
- @Override
- publicvoid onCollectionRecreate(Object collection, Serializable key)
- throws CallbackException {
- System.out.println("recreate..............");
- super.onCollectionRecreate(collection, key);
- }
- @Override
- publicvoid onCollectionRemove(Object collection, Serializable key)
- throws CallbackException {
- System.out.println("remove..............");
- super.onCollectionRemove(collection, key);
- }
- @Override
- publicvoid onCollectionUpdate(Object collection, Serializable key)
- throws CallbackException {
- System.out.println("collectionUpdate..............");
- super.onCollectionUpdate(collection, key);
- }
- @Override
- publicboolean onLoad(Object entity, Serializable id, Object[] state,
- String[] propertyNames, Type[] types) {
- System.out.println("load..............");
- returnsuper.onLoad(entity, id, state, propertyNames, types);
- }
- @Override
- publicvoid postFlush(Iterator entities) {
- System.out.println("flush..............");
- super.postFlush(entities);
- }
- @Override
- public String onPrepareStatement(String sql) {
- System.out.println("statement.............."+sql);
- returnsuper.onPrepareStatement(sql);
- }
- @Override
- publicvoid preFlush(Iterator entities) {
- System.out.println("preflush..............");
- super.preFlush(entities);
- }
- }
類繼承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中加
- <property name="entityInterceptor">
- <ref bean="cacheIntercepter"/>
- </property>
事件監聽器實現:
[java] view plaincopyprint?- package fi.uum.cache.listener;
- import org.hibernate.event.spi.PostDeleteEvent;
- import org.hibernate.event.spi.PostDeleteEventListener;
- import org.hibernate.event.spi.PostInsertEvent;
- import org.hibernate.event.spi.PostInsertEventListener;
- import org.hibernate.event.spi.PostUpdateEvent;
- import org.hibernate.event.spi.PostUpdateEventListener;
- import org.hibernate.persister.entity.EntityPersister;
- import org.springframework.stereotype.Component;
- @Component
- publicclass CacheEventListener implements PostUpdateEventListener ,
- PostInsertEventListener,PostDeleteEventListener{
- /**
- *
- */
- privatestaticfinallong serialVersionUID = 1L;
- @Override
- publicvoid onPostDelete(PostDeleteEvent arg0) {
- System.out.println("delete...................");
- }
- @Override
- publicvoid onPostInsert(PostInsertEvent arg0) {
- System.out.println("insert...................");
- }
- @Override
- publicvoid onPostUpdate(PostUpdateEvent arg0) {
- System.out.println("update...................");
- }
- @Override
- publicboolean requiresPostCommitHanding(EntityPersister arg0) {
- System.out.println("here...................");
- returnfalse;
- }
- }
配置方法:
在hibernate4中,檢視LocalSessionFactroyBean原始碼去不支援EventListener。spring3.X 對hibernate4不支援這樣的配置,hibernate4 改變了註冊EventListener的方式,這裡使用註解方式:
- package fi.uum.common.config;
- import javax.annotation.PostConstruct;
- import org.hibernate.SessionFactory;
- import org.hibernate.event.service.spi.EventListenerRegistry;
- import org.hibernate.event.spi.EventType;
- import org.hibernate.internal.SessionFactoryImpl;
- import org.springframework.bea