回顾hibernate refernce,在自定义hibernate intecerptor,events listencer模块,假设了个实现针对某个对象数据操作,要求实现操作日志的记录的功能需求,以下是实现方案的记录:
方案1:采用hibernate interceptor实现:
public class SampleEntityInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 1L;
protected Log logger = LogFactory.getLog(SampleEntityInterceptor.class);
@Override
public void onDelete(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
logger.info(" ### SampleEntityInterceptor.onDelete:");
// process......
}
@Override
public boolean onLoad(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
logger.info(" ### SampleEntityInterceptor.onLoad:");
// process......
return false;
}
@Override
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
logger.info(" ### SampleEntityInterceptor.onSave:");
// process......
return false;
}
}
spring配置:
<!-- 自定义Hibernate Entity Interceptor -->
<bean id="sampleEntityInterceptor" class="org.hook.hibernate.domain.interceptor.SampleEntityInterceptor" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="namingStrategy">
<bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
</property>
<property name="hibernateProperties">
<props>
......
</props>
</property>
<property name="packagesToScan" value="org.hook.hibernate.domain.*"/>
<property name="entityInterceptor">
<ref bean="sampleEntityInterceptor"/>
</property>
</bean>
在
SampleEntityInterceptor 中即可对拥有自定义Annotation的entity填充操作日志信息。
缺点:把日志信息分散到entity属性中,不利于统一管理和维护。
方案2:采用hibernate eventlistener实现:
public class SampleDefaultLoadEventListener extends DefaultLoadEventListener {
private static final long serialVersionUID = 1L;
protected Log logger = LogFactory
.getLog(SampleDefaultLoadEventListener.class);
@Override
public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
throws HibernateException {
super.onLoad(event, loadType);
logger.info(" ### SampleDefaultLoadEventListener.onLoad:");
// process......
}
}
spring配置:
<bean id="sampleDefaultLoadEventListener" class="org.hook.hibernate.domain.eventlistener.SampleDefaultLoadEventListener" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="namingStrategy">
<bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
</property>
<property name="hibernateProperties">
<props>
......
</props>
</property>
<property name="packagesToScan" value="org.hook.hibernate.domain.*"/>
<property name="entityInterceptor">
<ref bean="sampleEntityInterceptor"/>
</property>
<property name="eventListeners">
<map>
<entry key="load">
<ref bean="sampleDefaultLoadEventListener" />
</entry>
</map>
</property>
</bean>
通过event.getSession()可获取到hibernate session.
另外,需要注意的是,spring提供对sessionfactory的封装实现中(这里采用的是AnnotationSessionFactoryBean),所继承的父类在注入eventerlistener时,提供的是个map属性,所以自定义listener只能采用继承Default listener的方式实现。
附上LocalSessionFactoryBean对eventerlistener的初始化代码:
if (this.eventListeners != null) {
// Register specified Hibernate event listeners.
for (Iterator it = this.eventListeners.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
Assert.isTrue(entry.getKey() instanceof String, "Event listener key needs to be of type String");
String listenerType = (String) entry.getKey();
Object listenerObject = entry.getValue();
if (listenerObject instanceof Collection) {
Collection listeners = (Collection) listenerObject;
EventListeners listenerRegistry = config.getEventListeners();
Object[] listenerArray =
(Object[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size());
listenerArray = listeners.toArray(listenerArray);
config.setListeners(listenerType, listenerArray);
}
else {
config.setListener(listenerType, listenerObject);
}
}
}