该篇文章是接前几篇文章补充的:spring3 hibernate4 如何支持EventListener
之前的文章中虽然搭建,测试都成功了,但是在真正使用时还是有遇到难题,先说下本来在开发的过程中遇到的问题情况:
一般我们项目中的实体类(entity)都有几个共用的属性,比如:ID,createDate(创建时间),delFlag(删除标记)。如果我们每次在新增的时候去设置这几个属性会变的很繁琐,所以这时候就考虑到了在执行savaOrupdate方法的时候,用一个统一的方法对这几个属性进行赋值,然后再进行save 或者update操作。
下面是我当时写的代码:
package com.pengtu.gsj.dao.hibernate;
import org.hibernate.HibernateException;
import org.hibernate.event.internal.DefaultSaveOrUpdateEventListener;
import org.hibernate.event.spi.SaveOrUpdateEvent;
import org.springframework.util.StringUtils;
import com.pengtu.gsj.entity.IdEntity;
import com.pengtu.gsj.utils.Constants;
import com.pengtu.gsj.utils.DateUtils;
/**
* @author zl
* @version 创建时间:2017年3月30日 上午11:16:47
* 在hibernate执行saveOrUpdate()时,自动为IdEntity的子类添加信息.
*/
public class AccountSaveUpdateEventListener extends
DefaultSaveOrUpdateEventListener {
private static final long serialVersionUID = -5890362089838366308L;
@Override
public void onSaveOrUpdate(SaveOrUpdateEvent event)
throws HibernateException {
Object object = event.getObject();
if (object instanceof IdEntity) {
IdEntity entity = (IdEntity) object;
if (StringUtils.isEmpty(entity.getId())) {
entity.setId(null); //创建新的对象
entity.setDelFlag(Constants.DELFLAG_IN);
entity.setCreateDate(DateUtils.getCurrentDate());
}
}
super.onSaveOrUpdate(event);
}
}
运行程序,程序能正常跑起来,就是每次执行save操作的时候,到了监听器中,判断id是否存在的时候,实体类已经有了id值,这让createDate和Deflag没有办法进行赋值,那怎么让每个实体类在保存的时候进到这个监听器中的方法时id是没有值的呢?
因为该监听器是从上一个项目中借鉴过来的,但是上一个项目用的是hibernate3 和hibernate4配置不同,我对比了所有的内容,但是出了配置这块不同外其他内容都相同,我自认为代码是没有问题的,所以一直以为是hibernate4的机制和hibernate3不同,困扰了一天的时间,一直没有解决,但是该功能又是必须的,怎么办? 全部撤回,用hibernate3? 不是没有想过,但是还是拒绝了。
因为对待一个新的技术或者一个新的问题,如果你连尝试去解决它的勇气都没有,那就配不上进步。(有点鸡汤了哈 。。。可以忽略)
后面使用了debug模式,寻找id在什么地方生成的,最后发现id是在DefaultSaveOrUpdateEventListener中生成的,见代码:
// For an uninitialized proxy, noop, don't even need to return an id, since it is never a save()
if ( reassociateIfUninitializedProxy( object, source ) ) {
LOG.trace( "Reassociated uninitialized proxy" );
}
else {
//initialize properties of the event:
final Object entity = source.getPersistenceContext().unproxyAndReassociate( object );
event.setEntity( entity );
event.setEntry( source.getPersistenceContext().getEntry( entity ) );
//return the id in the event object
event.setResultId( performSaveOrUpdate( event ) );
}
执行该默认监听之后才进去我们自定义的监听,当然实体就会有id了, 如果最开始先进我们自定义的监听器再去其他监听器那就是最完美的,基本确定是
监听器的顺序问题,那怎么解决呢?
我去阅读了hibernate4的源代码,里面有对监听器的一段说明,阅读之后就懂了: 下面是hibernate4的源码片段
public class MyIntegrator implements org.hibernate.integrator.spi.Integrator {
public void integrate(
Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
// As you might expect, an EventListenerRegistry is the thing with which event listeners are registered It is a
// service so we look it up using the service registry
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
// If you wish to have custom determination and handling of "duplicate" listeners, you would have to add an
// implementation of the org.hibernate.event.service.spi.DuplicationStrategy contract like this
eventListenerRegistry.addDuplicationStrategy( myDuplicationStrategy );
// EventListenerRegistry defines 3 ways to register listeners:
// 1) This form overrides any existing registrations with
eventListenerRegistry.setListeners( EventType.AUTO_FLUSH, myCompleteSetOfListeners );
// 2) This form adds the specified listener(s) to the beginning of the listener chain
eventListenerRegistry.prependListeners( EventType.AUTO_FLUSH, myListenersToBeCalledFirst );
// 3) This form adds the specified listener(s) to the end of the listener chain
eventListenerRegistry.appendListeners( EventType.AUTO_FLUSH, myListenersToBeCalledLast );
}
}
看到注解和方法名,我发现我使用的方法是 eventListenerRegistry.appendListeners
顿时明白了,自定义的监听器为什么在最后执行了,最后将HibernateEventWiring类中的方法修改了一下:
修改之前:
eventListenerRegistry.getEventListenerGroup(eventType).appendListener(listeners.get(key));
修改之后:
eventListenerRegistry.getEventListenerGroup(eventType).prependListener(listeners.get(key));
修改之后再进行测试操作,一切正常!解决了
愉快的过周末了!