关于hibrenate中拦截器与事件监听器的介绍和使用的文章可以参看这篇文章:
Hibernate拦截器(Interceptor)与事件监听器(Listener)
关于在hibernate中使用拦截器实现增删改查日志记录的文章可参看这篇文章:
Hibernate4 拦截器(Interceptor) 实现实体类增删改的日志记录
拦截器与事件监听器的区别在于
监听器比拦截器提供更加细粒度的控制
监听器可以提供以下几种级别的事件的监听:
而拦截器只提供以下几种事件的监听:
2. 监听器比拦截器更加底层,拦截器是在对应的监听器中被启动的,这点可以看hibernate的代码,比如在org.hibernate.event.internal.DefaultFlushEntityEventListener中调用了对应的拦截器,代码如下:
protected boolean invokeInterceptor(
SessionImplementor session,
Object entity,
EntityEntry entry,
final Object[] values,
EntityPersister persister) {
return session.getInterceptor().onFlushDirty(
entity,
entry.getId(),
values,
entry.getLoadedState(),
persister.getPropertyNames(),
persister.getPropertyTypes()
);
}
3.在监听器中可以取到session,但在拦截器中不行,比如前面那篇用拦截器实现增删改查日志的例子中只能很无奈的调用HibernateUtil.getSessionFactory().openSession()来重新打开一个session了,但在监听器中可以通过AbstractEvent的getSession方法来获取session,如下:
protected boolean handleInterception(FlushEntityEvent event) {
SessionImplementor session = event.getSession();
4.但拦截器使用起来会比监听器直观,比如同样是想监听同步数据库前实体的状态,用拦截器的onFlushDirty方法可以很直接的取到更新前的状态和更新后的值,如下:
public boolean onFlushDirty(
Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
其中,currentState是更新后的值,previousState是更新前的值。
而如果用监听器的话,需要先通过event中获取到对应的持久化实例,再从实例中获取到对应的属性,如下是在DefaultFlushEntityEventListener类中调用拦截器的过程:
EntityEntry entry = event.getEntityEntry();
EntityPersister persister = entry.getPersister();
Object entity = event.getEntity();
final Object[] values = event.getPropertyValues();
final boolean intercepted = invokeInterceptor( session, entity, entry, values, persister );
protected boolean invokeInterceptor(
SessionImplementor session,
Object entity,
EntityEntry entry,
final Object[] values,
EntityPersister persister) {
return session.getInterceptor().onFlushDirty(
entity,
entry.getId(),
values,
entry.getLoadedState(),
persister.getPropertyNames(),
persister.getPropertyTypes()
);
}
所以综上几点,如果不需要非常细粒度的监听hibernate中的事件的话优先使用拦截器,但如果想在监听的同时获取到sessionc对象的又不想重新打开一个session的话请务必使用监听器。