回顧hibernate refernce,在自定義hibernate intecerptor,events listencer模塊,假設了個實現針對某個對象數據操作,要求實現操作日志的記錄的功能需求,以下是實現方案的記錄:
方案1:采用hibernate interceptor實現:
缺點:把日志信息分散到entity屬性中,不利于統一管理和維護。
方案2:采用hibernate eventlistener實現:
另外,需要注意的是,spring提供對sessionfactory的封裝實現中(這里采用的是AnnotationSessionFactoryBean),所繼承的父類在注入eventerlistener時,提供的是個map屬性,所以自定義listener只能采用繼承Default listener的方式實現。
附上LocalSessionFactoryBean對eventerlistener的初始化代碼:
方案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配置: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;
}
}
<!-- 自定義Hibernate Entity Interceptor -->
<bean id="sampleEntityInterceptor" class="org.hook.hibernate.domain.interceptor.SampleEntityInterceptor" />
<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填充操作日志信息。<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>
缺點:把日志信息分散到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配置: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......
}
}
<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.<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>
另外,需要注意的是,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);
}
}
}
// 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);
}
}
}