[读书总结]Hibernate的事件框架

   通常,载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.getSessionEventListenerConfig().setLoadEventListener(
               new MyLoadListener());
            sessionFactory = cfg.configure().buildSessionFactory();
   
         } catch(Throwable ex) {
            System.err.println("初始化sessionFactory失败。" + ex);
            throw new ExceptionInInitializerError(ex);
         } 
      }
      
      使用声明式方式使用自定义监听器时,可在Hibernate配置文件中的<session-factory>元素中增加:
         <listener type="load" class="MyLoadListener">
子元素即可。
      使用配置文件注册事件监听器虽然方便,但也有不利之处:通过配置文件注册的监视器不能共享实例;如果有多个<listener/>元素中使用了相同的类,则每个引用都将产生一个新拦截器实例;如果需要在多个事件之间共享监听器的实例,则必须使用编程式方式来注册事件监听器。
      虽然监听器类实现了特定监听器的接口,但在注册时还要明确指出注册的事件。因为一个类可能实现多个监听器的接口,所以,在注册时明确指定要监听的事件,可以使得启用或者禁用某个事件的监听配置工作更加简单。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值