前言:

由于项目中(S2SH框架)用到了memcache缓存服务器,考虑到同步问题是用每个bean变更时同时更新缓存还是用类似数据库trigger(触发器)去实现呢,答案当然是用类似trigger的方式了,其优点不言而喻,毕竟这么写一劳永逸。

经调查发现,hibernate有两种方式可以实现:

拦截器(Intercept):与Struts2的拦截器机制基本一样,都是一个操作穿过一层层拦截器,每穿过一个拦截器就会触发相应拦截器的事件做预处理或善后处理。

监听器(Listener):其实功能与拦截器是相似的,但它实现原理不同,它是为每一个事件注册一个或多个监听器,一旦事件发生,则事件源通知所有监听该事件的监听器,然后监听器处理通知(观察者模式)。

拦截器具体实现:

  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. public class CacheIntercepter extends EmptyInterceptor{
  10. /**
  11. *
  12. */
  13. private static final long serialVersionUID = 1L;
  14. @Override
  15. public void 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. public boolean onFlushDirty(Object entity, Serializable id,
  22. Object[] currentState, Object[] previousState,
  23. String[] propertyNames, Type[] types) {
  24. System.out.println(“flushDirty…………..”);
  25. return super.onFlushDirty(entity, id, currentState, previousState,
  26. propertyNames, types);
  27. }
  28. @Override
  29. public boolean onSave(Object entity, Serializable id, Object[] state,
  30. String[] propertyNames, Type[] types) {
  31. System.out.println(“save…………..”);
  32. return super.onSave(entity, id, state, propertyNames, types);
  33. }
  34. @Override
  35. public void onCollectionRecreate(Object collection, Serializable key)
  36. throws CallbackException {
  37. System.out.println(“recreate…………..”);
  38. super.onCollectionRecreate(collection, key);
  39. }
  40. @Override
  41. public void onCollectionRemove(Object collection, Serializable key)
  42. throws CallbackException {
  43. System.out.println(“remove…………..”);
  44. super.onCollectionRemove(collection, key);
  45. }
  46. @Override
  47. public void onCollectionUpdate(Object collection, Serializable key)
  48. throws CallbackException {
  49. System.out.println(“collectionUpdate…………..”);
  50. super.onCollectionUpdate(collection, key);
  51. }
  52. @Override
  53. public boolean onLoad(Object entity, Serializable id, Object[] state,
  54. String[] propertyNames, Type[] types) {
  55. System.out.println(“load…………..”);
  56. return super.onLoad(entity, id, state, propertyNames, types);
  57. }
  58. @Override
  59. public void 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. return super.onPrepareStatement(sql);
  67. }
  68. @Override
  69. public void 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中加

  1. <property name=“entityInterceptor”>
  2. <ref bean=“cacheIntercepter”/>
  3. </property>

事件监听器实现:

  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. public class CacheEventListener implements PostUpdateEventListener ,
  12. PostInsertEventListener,PostDeleteEventListener{
  13. private static final long serialVersionUID = 1L;
  14. @Override
  15. public void onPostDelete(PostDeleteEvent arg0) {
  16. System.out.println(“delete……………….”);
  17. }
  18. @Override
  19. public void onPostInsert(PostInsertEvent arg0) {
  20. System.out.println(“insert……………….”);
  21. }
  22. @Override
  23. public void onPostUpdate(PostUpdateEvent arg0) {
  24. System.out.println(“update……………….”);
  25. }
  26. @Override
  27. public boolean requiresPostCommitHanding(EntityPersister arg0) {
  28. System.out.println(“here……………….”);
  29. return false;
  30. }
  31. }

配置方法:

在hibernate4中,查看LocalSessionFactroyBean源码去不支持EventListener。spring3.X 对hibernate4不支持这样的配置,hibernate4 改变了注册EventListener的方式,这里使用注解方式:

  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.beans.factory.annotation.Autowired;
  8. import org.springframework.stereotype.Component;
  9. import fi.uum.cache.listener.CacheEventListener;
  10. @Component
  11. public class HibernateIntegrator {
  12. @Autowired
  13. private CacheEventListener cacheEventListener;
  14. @Autowired
  15. private SessionFactory sessionFactory;
  16. @PostConstruct
  17. public void registerListeners() {
  18. EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(
  19. EventListenerRegistry.class);
  20. registry.getEventListenerGroup(EventType.POST_INSERT).appendListener(cacheEventListener);
  21. registry.getEventListenerGroup(EventType.POST_UPDATE).appendListener(cacheEventListener);
  22. registry.getEventListenerGroup(EventType.POST_DELETE).appendListener(cacheEventListener);
  23. }
  24. }

 

如果你的项目使用的是hibernate3+,建议在sessionFactory bean中配置eventListener。

实际效果:

两种方法实现过发现在本项目中只有save obj的时候才触发了事件(拦截器),一直不解,后来想到hibernate是基于对象操作的,而在项目中除了save方法外,其他的update、delete、等方法都是通过hql语句实现的,所有更新、删除的事件未触发。这样一来必须通过监听statement语句时通过判断该如果是更新还是删除等执行更新缓存了。

Proguard使用最新,最全教程,亲自试验

最近公司有一个项目,是外包项目,由于对方也有技术人员,出于技术上的保密,需要对class文件进行二次处理,于是网上找了好久,只发现Proguard是用的最广泛...

阅读全文

获取用户IP的正确姿势

如何获取用户的IP,这个需求简直是太常见了,像登录入口,注册入口,投票,日志记录,api接口中判断同一个ip单位时间内的请求数,可是怎么去获取用户的真实...

阅读全文

将WordPress安装到网站子目录不改URL的方法

首先,在根目录安装好WordPress,然后将根目录中的WordPress所有内容移到你想要的子目录中。 在根目录中创建一个名为 .htaccess的文件, 内容如下,你只...

阅读全文

评论已经关闭。