通常,载Hibernate执行持久化的过程中,应用程序无法参与其中。因为所有的数据持久化操作,对用户都是透明的,所以用户无法加入自己的动作。
通过事件框架,Hibernate允许应用程序能响应特定的内部事件,从而实现某些通用的功能,或者允许对Hibernate功能进行扩展。
Hibernate的事件框架由以下两部分组成。
●拦截器机制:对于特定动作拦截,回调应用中的特定动作。
●事件系统:重写Hibernate的事件监听器。
1.拦截器:
通过Inteceptor接口,可以从Session中回调应用程序的特定方法,这种回调机制可让应用程序在持久化对象被保存,更新,删除或加载之前,对其进行检查并修改其属性。
通过Inteceptor接口,可以在数据进入数据库之前,对数据进行最后的检查,如果数据不符合要求,则可以修改,从而避免非法数据进入数据库。当然,通常无须这样做,只有在某些特殊的场合下,才考虑使用拦截器完成检查功能。
使用拦截器时按如下步骤进行:
(1)定义实现Interceptor接口的拦截器类。
(2)通过Session起用拦截器,或者通过Configuration启用全局拦截器。
下面是一个拦截器的简单示例的代码:
public class MyInterceptor extends EmptyInterceptor {
public void onDelete(Object entity,Serializable id,Object[] state,
String[] propertyNames,Type[] types) {
System.out.println("该方法在删除数据时调用");
}
}
拦截器的使用有两种方法:
●通过SessionFactory的openSession(Interceptor in)方法打开一个带局部拦截器的Session。
●同过Configuration的setInterceptor(Interceptor in)方法设置全局拦截器。
下面是使用拦截器的示例的部分代码:
public class HibernateUtil {
public static final SessionFactory sessionFactory;
static{
try{
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}catch (Throwable ex) {
System.err.println("初始化sessionFactory失败。" + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession(Interceptor it) throws HibernateException {
Session s = (Session) session.get();
if(s == null) {
s = sessionFactory.openSession(it);
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
if (s != null)
s.close();
session.set(null);
}
}
2.事件系统:
Hibernate3事件系统是功能更强大的事件框架,该事件系统可以替代拦截器,也可以作为拦截器的补充来使用。
基本上,Session接口的每个方法都有对应的事件。比如LoadEvent,FlushEvent等。事实上,当Session调用某方法时,Hibernate Session会生成对应的事件,并激活对应的事件监听器。在系统默认监听器实现的处理过程中,完成了对所有的数据持久化的操作,包括插入和修改等操作。如果用户定义了自己的监听器,则意味着用户必须完成对象的持久化操作。
例如,可以在系统中实现并注册LoadEventListener,该监听器负责处理所有调用Session的load()的方法的请求。
由于监听器是单态模式对象,即所有的同类型的事件处理共享同一个监听器实例,因此,此监听器不应该保存任何状态,即不应该使用成员变量。
使用事件系统时按如下步骤进行:
(1)实现自己的事件监听器类。
(2)注册自定义事件监听器,代替系统默认的事件监听器。
实现用户的自定义监听器有如下三个方法:
●实现对应的监听器接口:这是不可思议的,实现接口必须实现接口内的所有方法,关键是必须实现Hibernate对应的持久化操作,即数据库访问,这意味着程序员完全取代了Hibernate的底层操作。
●继承事件适配器:可以选择地实现需要关注的方法,但依然需要替代Hibernate完成数据库访问。这也不太现实。
●继承系统默认的事件监听器:扩展特定的方法。
实际上,前两种方法很少使用。因为Hibernate的持久化操作也是通过这些监听器实现的,如果用户取代了这些监听器,则应该自己实现持久化操作,这意味着用户放弃了Hibernate的持久化操作,而改为自己完成Hibernate的核心操作。
通常我们采用第三种方法实现自己的事件监听器。因为Hibernate默认的事件监听器被声明成non-final,从而方便用户继承。
下面是用户自定义监听器的示例:
//自定义LoadListener,继承默认的DefaultLoadEventListener实现类
public class MyLoadListener extends DefaultLoadEventListener {
//在LoadEventListener接口仅仅定义了这个方法
public Object onLoad(LoadEvent event,LoadEventListener.LoadType loadType)
throws HibernateException {
Object o = super.onLoad(event,loadType);
System.out.println("自定义的load事件");
System.out.println(event.getEntityClassName() + "---------"
+ event.getEntityId());
return o;
}
}
注册用户自定义监听器也有以下两种方法。
●编程式:通过使用Configuration对象编程注册。
●声明式:在Hibernate的XML格式的配置文件中进行声明,使用Properties格式的配置文件将无法配置自定义监听器。
通过编程式方式使用自定义监听器时,只需将HibernateUtil中的静态块儿用如下的静态块儿替代即可:
static{
try{
Configuration cfg = new Configuration();
cfg.getSes
sionEventListenerConfig().setLoadEventListener(
new MyLoadListener());
sessionFactory = cfg.configure().buildSessionFactory();
} catch(Throwable ex) {
System.err.println("初始化sessionFactory失败。" + ex);
throw new ExceptionInInitializerError(ex);
}
}
使用声明式方式使用自定义监听器时,可在Hibernate配置文件中的元素中增加:
子元素即可。
使用配置文件注册事件监听器虽然方便,但也有不利之处:通过配置文件注册的监视器不能共享实例;如果有多个元素中使用了相同的类,则每个引用都将产生一个新拦截器实例;如果需要在多个事件之间共享监听器的实例,则必须使用编程式方式来注册事件监听器。
虽然监听器类实现了特定监听器的接口,但在注册时还要明确指出注册的事件。因为一个类可能实现多个监听器的接口,所以,在注册时明确指定要监听的事件,可以使得启用或者禁用某个事件的监听配置工作更加简单。
阅读(1028) | 评论(0) | 转发(0) |