论坛首页 Java企业应用论坛

EJB3.0拦截器拦截生命周期事件

浏览 2512 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-04-25  
你不仅能拦截EJB方法的调用,也可以拦截EJB生命周期事件.这些回调可以被用于初始化你的EJB组件类的状态,如同拦截器类本身.生命周期的拦截非常类似于@AroundInvoke 类型:
@<callback-annotation> void
<method-name>(InvocationContext
ctx);
要想拦截一个EJB的回调,定义一个方法在你的拦截器类中与你感兴趣的回调一起注释.方法的返回值必需是void因为EJB回调没有返回值.方法名可以是任意的并且必需不抛出任何检查异常(没有throws子句).InvocationContext是这个方法的唯一参数.同@AroundInvoke方法,回调拦截的调用在一个大的Java调用栈中.这意味着你必需调用InvocationContext.proceed( )方法来完成生命周期事件.当proceed( )被调用时下一个拦截器类的相同回调被调用.如果没有其它的回调方法,那么proceed( )是一个no-op.因为没有回调方法InvocationContext.getMethod( )方法总是返回null.

定制注入注释
为什么要拦截一个EJB的回调?一个具体的例子是当你想要创建和定义你自己的注入注释.EJB规范中有一组注释为你注入J2EE资源,服务,和EJB引用到你的组件类中.一些应用程序服务器或应用程序像使用JNDI作为全局注册配置或没有J2EE服务的.不幸的是,规范定义没有方法直接注入全局的JNDI到你的组件中.我们怎样做来定义我们自己的注释提供这种功能和实现它作为一个拦截器.
首先我们要做的是定义我们将要使用从JNDI注入的注释:
package com.titan.annotations;

import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JndiInjected {
   String value( );
}
@com.titan.annotations.JndiInjected注释的value()属性是对象的全局JNDI名字,我们想要注入的字段或setter方法.这是一个我们怎样使用自定义注释的例子:
@Stateless
public class MySessionBean implements MySession {
   @JndiInject("java:/TransactionManager")
   private javax.transaction.TransactionManager tm;
...
}
一些应用程序可能感兴趣的是获取一个引用到J2EE JTA事务管理服务.很多应用程序服务存储一个引用到这个服务在全局JNDI中.在这种情况下,我们使用@JndiInjected注释进入到会话Bean的字段直接的引用事务管理.现在我们定义了我们自定义的注入注释并且我们定义了怎样使用它,我们需要实现拦截器类的代码实现它的行为:
package com.titan.interceptors;

import java.lang.reflect.*;
import com.titan.annotations.JndiInjected;
import javax.ejb.*;
import javax.naming.*;
import javax.interceptor.*;
import javax.annotation.*;

public class JndiInjector
{

   @PostConstruct
   public void jndiInject(InvocationContext invocation) {
      Object target = invocation.getTarget( );
      Field[] fields = target.getClass().getDeclaredFields( );
      Method[] methods = target.getClass().getDeclaredMethods( );

      // find all @JndiInjected
fields/methods and set them
      try {
         InitialContext ctx = new InitialContext( );
         for (Method method : methods) {
            JndiInjected inject = method.getAnnotation(JndiInjected.class);
            if (inject != null) {
               Object obj = ctx.lookup(inject.value( ));
               method.setAccessible(true);
               method.invoke(target, obj);
            }
         }
         for (Field field : fields) {
            JndiInjected inject = field.getAnnotation(JndiInjected.class);
            if (inject != null) {
               Object obj = ctx.lookup(inject.value( ));
               field.setAccessible(true);
               field.set(target, obj);
            }
         }
         invocation.proceed( );
      } catch (Exception ex) {
         throw new EJBException

("Failed to execute @JndiInjected", ex);
      }
   }
}
使用@javax.annotation.PostConstruct注释的jndiInject( )方法,告诉EJB容器JndiInjector拦截器感兴趣的是拦截指定的EJB回调.方法开始通过获取一个引用到组件实例它截取.通过反射来查找@JndiInjected对象的所有方法和字段.查找引用的JNDI名字,并且初始化目标组件实例的字段或方法.注意这是在try/catch 块中来做的.当拦截一个回调方法,你可以不用抛出检查异常:因此,所有的检查异常必需被捕获和包装在一个EJBException.
现在拦截器类已经被实现,我们可以应用拦截器到我们的组件当中:
<ejb-jar>
   <assembly-descriptor>
      <interceptor-binding>
         <ejb-name>*</ejb-name>
         <interceptor-class>com.titan.interceptors.JndiInjector

</interceptor-class>
      </interceptor-binding>
   </assembly-descriptor>
</ejb-jar>
这个例子中一个特别有趣而且显著的事情是你可以使用EJB拦截器作为一个框架为你写的自定义注释增加你想要的行为到EJB中.默认的拦截器,通过XML,给你一个简洁,简单的应用拦截器的实现行为在注释中.最后,这种自定义的行为是轻便的并且可以用在任意厂商来实现.不仅仅是EJB3.0容易使用,此外,最终还要易于扩展.
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics