Hibernate拦截器与事件系统

应用程序能够响应 Hibernate 内部产生的特定事件是非常有用的。这样就允许实现某些通用的功能以及允许对 Hibernate 功能进行扩展。

持久层框架底层的拦截器机制是对诸如 Spring 等业务管理容器拦截机制的有益补充,使得我们可以在更低层次、更广的对象范围上进行 AOP 操作(Spring虽然将Hibernate纳入到其容器管理的范围内,但是并没有途径实现对实体对象的管理)。这样就允许实现某些通用的功能,以及允许对 Hibernate 功能进行扩展。

一、拦截器(org.hibernate.Interceptor)

Interceptor 接口提供了从会话(session)回调(callback)应用程序(application)的机制,这种回调机制可以允许应用程序在持久化对象被保存、更新、删除或是加载之前,检查并(或)修改其属性。

Interceptor 接口提供了很多方法,我们可以通过继承 EmptyInterceptor 类来构造我们需要的方法实现。

拦截器可以有两种:

  • Session 范围内的
  • SessionFactory 范围内的

二、使用拦截器的步骤

(1)定义实现 Interceptor 接口(或继承 EmptyInterceptor)的拦截器类;
(2)通过 Session 启用拦截器,或者通过 Configuration 启用拦截器;

  • 当使用某个重载的 SessionFactory.openSession()使用 Interceptor 作为参数调用打开一个 session 的时候,就指定了 Session 范围内的拦截器。
Session session = sessionFactory.openSession(new MyInterceptor());
  • SessionFactory 范围内的拦截器要通过 Configuration 中注册,而且这必须在创建 SessionFactory 之前。在这种情况下,给出的拦截器会被这个SessionFactory所打开的所有 session 使用,除非 session 打开时明确指明了使用的拦截器。SessionFactory范围内的拦截器,必须是线程安全的,因为多个session可能并发使用这个拦截器,要因此小心不要保存与session相关的状态。
new Configuration().setInterceptor(new MyInterceptor());

三、事件系统(Event system)

如果需要响应持久层的某些特殊事件,你也可以使用 Hibernate3 的事件框架。该事件系统可以用来代替拦截器,也可以作为拦截器的补充来使用。

基本上,Session接口的每个方法都有相应的事件。比如 LoadEvent,FlushEvent,等等(可以查阅XML配置文件的DTD以及org.hibernate.event包来获得所有已定义的事件的列表)。

当某个方法被调用时,Hibernate Session 会生成一个相应的事件并激活所有配置好的事件监听器(观察者模式)。被监听的方法所做的其实仅仅是激活监听器,“实际”的工作是由监听器完成的。你可以自由地选择实现一个自己定制的监听器:

比如,实现并注册来处理处理 LoadEvent 的 LoadEventListener 接口,来处理所有的调用 Session 的 load()方法的请求。

监听器在运行时被实例化为单例(singleton)对象,也就是说,所有同类型的事件的处理共享同一个监听器实例,因此监听器不应该保存任何与请求相关的状态。

用户定制的监听器需要实现相关的事件监听器接口,或者从一个合适的基类继承(甚至是从 Hibernate 自带的默认事件监听器类继承)。

用户定制的监听器可以通过编程使用 Configuration 对象来注册,也可以在 Hibernate 的 XML 格式的配置文件中进行声明。

//示例:
public class MyLoadlistener implements LoadEventListener{

    @Override
    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
        throws HibernateException{
        if(!MySecurity.isAuthorized(event.getEntityClassName(), event.getEntityId())){
            throw MySecurityException("Unauthorized access");
        }
    }
}

你还需要修改hibernate主配置文件中的一处配置,来告诉 Hibernate,除了默认的监听器,还要附加选定的监听器。

/*通过配置文件配置的方式注册监听器*/
<hibernate-configuration>
    <session-factory>
        ...
        <event type="load">
            <listener class="com.eg.MyLoadListener" />
            <listener class="org.hibernate.event.def.DefaultLoadEventListener" />
        </event>
    </session-factory>
</hibernate-configuration>
/*----------------------------------------------------*/
/*或通过编程的方式来注册监听器*/
Configuration cfg = new Configuration();
LoadEventListener[] stack = {new MyLoadListener(),new DefaultLoadEventListener()};
cfg.getEventListeners().setLoadEventListeners(stack);

通过在 XML 配置文件声明而注册的监听器不能共享实例。如果在多个<listener />节点中使用了相同的类的名字,则每一个引用都将会产生一个独立的实例。如果你需要在多个监听器类型之间共享监听器的实例,则你必须使用编程的方式来进行注册。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值