hibernate4 EventListener 后續--監聽順序的影響


該篇文章是接前幾篇文章補充的:spring3 hibernate4 如何支持EventListener

之前的文章中雖然搭建,測試都成功了,但是在真正使用時還是有遇到難題,先說下本來在開發的過程中遇到的問題情況:

一般我們項目中的實體類(entity)都有幾個共用的屬性,比如:IDcreateDate(創建時間)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));

修改之后再進行測試操作,一切正常!解決了

愉快的過周末了!



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com