hibernate的拦截与监听

理解Hibernate拦截器与事件监听机制实现审计日志
本文详细介绍了如何使用Hibernate的拦截器和事件监听机制实现数据库操作审计日志,包括拦截器方法的使用、配置审计日志、实现审计功能的步骤以及与事件监听器的区别。

拦截器(Interceptor)
org.hibernate.Interceptor接口定义了Hibernate中通用拦截机制
创建Session对象的时候,所有的Session对象或者这个Session对象的所有持久化操作的动作都会被指定的拦截器进行拦截.


Interceptor接口的方法

  • afterTransactionBegin()
    当一个事务时候启动时,会立刻调用这个方法,这个方法可以改变这个事务的状态,例如:回滚事务
  • instantiate()
    创建对象,如果返回null,则Hibernate将调用实体类的默认构造方法创建持久化对象
  • getEntity()
    当一个持久化对象,通过标示符属性在Session对象的缓存中进行查找,并且没有找到时,会调用该方法
  • getEntityName()
    当session对象获取持久化对象的名字时,会调用这个方法
  • onLoad()
    该方法在持久化对象初始化之前加载,这个的持久化对象处于刚被创建的状态(对象的属性值都未赋值)
  • findDirty()
    当调用Session对象的flush()方法时,讲调用该方法判断对象是否为脏数据,这是脏数据检查的另外拦截的实现方式
  • isTransient()
    当调用Session对象的saveOrUpdate方法时,会调用该方法判断对象是否尚未保存
  • onSave()
    在对象被保存之前调用,通过这个方法可以对要保持的对象的属性进行修改
  • onDelete()
    该方法在持久化对象被删除之前调用
  • preFlush()
    该方法当调用Session对象的flush()方法之前被调用
  • onFlushDirty()
    当调用Session对象flush()方法进行脏数据检查时,如果发现持久化对象的状态发生了改变,会调用该方法
  • postFlush()
    该方法调用Session对象的flush()方法之后被调用
  • beforeTransactionComplet<wbr>ion()<br> 在完成一个事务之前,调用此方法,这个方法可以改变事务的状态,例如回滚事务</wbr>
  • afterTransactionCompleti<wbr>on()<br> 当完成一个事务之后,立刻调用此方法</wbr>

使用拦截器实现审计日志
审计日志指的是,在应用系统中,对所有的数据库的操作都做记录,记录所操作内容,操作的用户和操作的时间

demo

log4j.properties

Log4j.properties代码 复制代码 收藏代码
  1. log4j.logger.com.rbh.examples=info,appender1
  2. log4j.appender.appender1=org.apache.log4j.FileAppender
  3. log4j.appender.appender1.layout=org.apache.log4j.TTCCLayout
  4. log4j.appender.appender1.File=ligfile.txt

LogEntityInterceptor

Java代码 复制代码 收藏代码
  1. packagecom.rbh.examples;
  2. importjava.io.Serializable;
  3. importorg.apache.log4j.Logger;
  4. importorg.hibernate.EmptyInterceptor;
  5. importorg.hibernate.type.Type;
  6. publicclassLogEntityInterceptorextendsEmptyInterceptor {
  7. privatestaticfinallongserialVersionUID = 1L;
  8. privateLogger logger = Logger.getLogger(LogEntityInterceptor.class);
  9. publicvoidonDelete(Object entity,Serializable id, Object[] state,String[] propertyNames,
  10. Type[] types){
  11. logger.info("删除数据");
  12. }
  13. publicbooleanonFlushDirty(Object entity,Serializable id, Object[] currentState,
  14. Object[] preState,String[] propertyNames,
  15. Type[] types){
  16. logger.info("修改数据");
  17. returnfalse;
  18. }
  19. publicbooleanonSave(Object entity,Serializable id, Object[] State,
  20. String[] propertyNames,
  21. Type[] types){
  22. logger.info("保存数据");
  23. returnfalse;
  24. }
  25. }

HibernateTest

Java代码 复制代码 收藏代码
  1. packagecom.rbh.examples;
  2. importjava.util.Date;
  3. importorg.hibernate.Session;
  4. importorg.hibernate.SessionFactory;
  5. importorg.hibernate.cfg.Configuration;
  6. publicclassHibernateTest {
  7. publicstaticvoidmain(String[] args)
  8. {
  9. HibernateTest test =newHibernateTest();
  10. test.testInterceptor();
  11. }
  12. publicvoidtestInterceptor()
  13. {
  14. LogEntityInterceptor interceptor=newLogEntityInterceptor();
  15. Configuration config=newConfiguration();
  16. config.setInterceptor(interceptor);
  17. config.configure();
  18. SessionFactory sf=config.buildSessionFactory();
  19. Session session=sf.getCurrentSession();
  20. Guestbook gb=newGuestbook();
  21. gb.setName("Narcissus");
  22. gb.setEmail("javac.q@gmail.com");
  23. gb.setCreatedTime(newDate());
  24. gb.setPhone("11102121");
  25. gb.setTitle("test Interceptor");
  26. gb.setContent("test Interceptor,test Interceptor");
  27. session.beginTransaction();
  28. session.save(gb);
  29. session.getTransaction().commit();
  30. session=sf.getCurrentSession();
  31. gb.setName("tom");
  32. session.beginTransaction();
  33. session.update(gb);
  34. session.getTransaction().commit();
  35. session=sf.getCurrentSession();
  36. session.beginTransaction();
  37. session.delete(gb);
  38. session.getTransaction().commit();
  39. }
  40. }

可以通过session方式加载拦截器对象,也可以通过Configuration对象加载拦截器

Configuration:对所有的session都会被拦截
session:只对当前的session进行拦截

Hibernate的事件监听机制

Hibernate中的事件监听机制可以对Session对象的动作进行监听,一旦发生了特殊的事件,Hibernate就会执行监听器中的事件处理方法

在某些功能的设计中,我们即可以使用Hibernate的拦截器实现,也可以使用Hibernate的事件监听来实现

Hibernate中事件与对应的监听器接口

事件类型 监听器接口

auto-flush AutoFlushEventListener
merge MergeEventListener
delete DeleteEventListener
persist PersistEventListener
dirty-check DirtyCheckEventListener
evice EvictEventListener
flush FlushEventListener
flush-entity FlushEntityEventListener<wbr><br> load LoadEventListener<br> load-collection InitializeCollectEventLi<wbr>stener<br> lock LockEventListener<br> refresh RefreshEventListener<br> replicate ReplicateEventListener<br> save-update SaveOrUpdateEventListene<wbr>r<br> pre-load PreLoadEventListener<br> pre-update PreUpdateEventListener<br> pre-delete PreDeleteEventListener<br> pre-insert PreInsertEventListener<br> post-load PostLoadEventListener<br> post-update PostUpdateEventListener<br> post-delete PostDeleteEventListener<br> post-insert PostInsertEventListener</wbr></wbr></wbr>


应用Hibernate事件监听器

用户制定的事件监听器首先需要实现与所需要处理的事件对应的接口,或者继承实现这个接口的类

通过使用Hibernate的配置文件(hibernate.cfg.xml)配置事件监听对象,或者使用Configuration对象注册这个定制的事件监听器对象

LogPostLoadEventListener<wbr></wbr>

Java代码 复制代码 收藏代码
  1. importorg.hibernate.event.PostLoadEvent;
  2. importorg.hibernate.event.PostLoadEventListener;
  3. publicclassLogPostLoadEventListener<wbr></wbr>implementsPostLoadEventListener {
  4. privatestaticfinallongserialVersionUID = 404241098418965422L;
  5. publicvoidonPostLoad(PostLoadEvent event) {
  6. System.out.println("Class:"+ event.getEntity().getClass().getName() +",id:"
  7. + event.getId());
  8. }
  9. }

修改Hibernate.cfg.xml文件

Xml代码 复制代码 收藏代码
  1. <mappingresource="com/rbh/examples/Guestbook.hbm.xml"/>
  2. <listenertype="post-load"class="com.rbh.examples.LogPostLoadEventListener<wbr>"</wbr>/>
  3. </session-factory>
  4. </hibernate-configuration>

或者通过Configuration 对象注册这个监听器对象

Java代码 复制代码 收藏代码
  1. Configuration config =newConfiguration();
  2. config.setListener("post-load",newLogPostLoadEventListener<wbr>());</wbr>
  3. config.configure();
  4. Session session = config.buildSessionFactory().getCurrentSession();

编写、配置好监听器以后,当通过Session对象的load()、get()方法或者Query对象的list方法加载持久化对象之后,LogPostEventListener对象中的onPostLoad()方法就会被执行.

使用监听器实现审计日志

利用Hibernate的事件机制,不仅能够精确追踪到持久化对象的字段的修改,持久化对象关联关系的变更,还能记录更新前的数值和更新后的数值

监听器与拦截器的比较

监听器可以实现更细化粒度的拦截
通过监听器获取所拦截的持久化对象的修改后喝修改前的状态值
能直接通过Event对象获取Session对象

<think>好的,我现在需要回答用户关于Hibernate的EmptyInterceptor使用实体监听的问题。首先,我得回忆一下Hibernate中的拦截器机制。记得Interceptor接口允许在持久化过程中拦截各种事件,而EmptyInterceptor是其适配器类,用户可以选择覆盖需要的方法。 接下来,用户提到的实体监听可能是指通过拦截器来监听实体的状态变化,比如保存、更新、删除或加载等操作。需要明确EmptyInterceptor和实体监听器(Entity Listeners)之间的区别。实体监听器通常使用注解如@PrePersist,而EmptyInterceptor更底层,适用于全局拦截,可以处理多个实体。 然后,我需要整理EmptyInterceptor的常用方法,比如onSave、onFlushDirty、onLoad、onDelete等,并举例说明如何继承这个类并覆盖这些方法。例如,在onSave方法中,用户可以在保存实体前修改其属性,或者在onLoad时修改加载后的实体数据。 同时,要注意配置拦截器的步骤,即在Hibernate配置中设置,或者通过SessionFactory获取Session时传入拦截器实例。需要给出具体的配置示例,比如在hibernate.cfg.xml中添加属性,或者在代码中设置。 此外,应该比较EmptyInterceptor和@EntityListeners的适用场景,指出前者适合全局处理,后者更细粒度地绑定到具体实体。还要提到可能的最佳实践,比如日志记录、审计跟踪或数据加密等应用场景。 最后,确保回答结构清晰,分步骤说明,并包含代码示例和配置说明,帮助用户逐步理解和实现。检查是否有LaTeX格式的问题,但根据用户指令,可能不需要,所以重点放在中文的清晰解释和正确代码示例上。</think>Hibernate的`EmptyInterceptor`是用于监听实体操作的核心拦截器,以下是分步解析和使用方法: 一、基础概念 1. `EmptyInterceptor`是`Interceptor`接口的适配器类 2. 提供空实现,开发者只需覆盖需要的方法 3. 可拦截的8个核心生命周期事件: - 实体保存前/后 - 实体更新前/后 - 实体加载时 - 实体删除前/后 - 脏检查时 - 事务结束时 二、实现步骤 1. 继承并实现自定义拦截器: ```java public class AuditInterceptor extends EmptyInterceptor { // 保存操作拦截(返回true会修改实体状态) @Override public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { if (entity instanceof Auditable) { System.out.println("拦截保存操作:" + entity.getClass().getName()); } return false; } // 更新操作拦截 @Override public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { if (entity instanceof Auditable) { System.out.println("拦截更新操作:" + entity.getClass().getName()); } return false; } } ``` 2. 配置拦截器(XML方式): ```xml <!-- hibernate.cfg.xml --> <session-factory> <property name="hibernate.session_factory.interceptor"> com.example.AuditInterceptor </property> </session-factory> ``` 3. 编程式配置(推荐方式): ```java Configuration cfg = new Configuration(); AuditInterceptor interceptor = new AuditInterceptor(); cfg.setInterceptor(interceptor); SessionFactory sf = cfg.buildSessionFactory(); ``` 三、高级应用场景 1. 数据审计跟踪(记录修改记录) ```java @Override public boolean onFlushDirty(...) { if (entity instanceof Auditable) { currentState[getIndex(propertyNames, "lastModified")] = new Date(); currentState[getIndex(propertyNames, "modifiedBy")] = getCurrentUser(); return true; // 必须返回true才会更新状态 } return false; } ``` 2. 数据加密拦截: ```java @Override public boolean onLoad(...) { if (entity instanceof Encryptable) { decryptFields(state, propertyNames); return true; } return false; } @Override public boolean onSave(...) { if (entity instanceof Encryptable) { encryptFields(state, propertyNames); return true; } return false; } ``` 四、@EntityListener对比 ``` | 特性 | EmptyInterceptor | @EntityListener | |--------------------|------------------------|-----------------------| | 作用范围 | 全局 | 单个实体类 | | 配置方式 | 编程式/XML | 注解 | | 执行顺序 | 更早(框架层拦截) | 较晚(实体层触发) | | 访问Session能力 | 可直接获取 | 需要通过回调接口 | | 多实体统一处理 | 支持 | 需每个类单独配置 | ``` 五、最佳实践建议 1. 优先使用拦截器的场景: - 需要横切多个实体的公共逻辑 - 需要Session直接交互的操作 - 低级别SQL/HQL操作拦截 2. 注意事项: - 避免在拦截器中执行业务逻辑 - 注意线程安全问题(建议设置为非全局作用域) - 谨慎处理返回值(返回true会修改持久化状态) 3. 性能优化技巧: ```java // 使用缓存提升属性索引查找效率 private int getIndex(String[] properties, String target) { return Arrays.asList(properties).indexOf(target); } ``` 六、调试技巧 1. 启用Hibernate日志: ```xml <logger name="org.hibernate" level="DEBUG"/> ``` 2. 使用拦截器堆栈(组合多个拦截器): ```java public class CompositeInterceptor extends EmptyInterceptor { private List<Interceptor> interceptors = new ArrayList<>(); public void addInterceptor(Interceptor interceptor) { interceptors.add(interceptor); } @Override public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { boolean modified = false; for (Interceptor interceptor : interceptors) { modified |= interceptor.onSave(entity, id, state, propertyNames, types); } return modified; } // 其他方法同理实现... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值