上一篇文章《会话EJB系列(四)SessionBean事务管理》中,我们介绍了SessionBean的事务管理机制。
本文主题‘拦截器’,详细介绍其用途、作用、与Spring框架AOP的对比,并介绍其初步用法。
一.简介
企业级应用中经常面对的事务管理、安全检查、缓存、对象池管理等,为此Spring框架提供了AOP方式,灵活控制业务方法!而EJB3没有提供AOP支持,那么他又是如何应对的呢?
JavaEE规范中提供的横切性服务:事务管理和安全检查。
EJB容器实现JavaEE规范
用CMT解决事务管理问题
用JAAS以声明的方式解决安全检查,权限控制。
而对于其它具有横切性质的服务,JavaEE规范依然显得力不从心。
为了弥补缺乏AOP支持的不足,EJB3提供了拦截器支持。
本质是轻量级AOP实现,作用于AOP如出一辙
将多个业务方法中通用逻辑从业务方法中抽离出来,放在拦截中实现,实现代码复用。
二.EJB3的拦截器和Spring的AOP对比
(一)不同点
Spring的AOP实现提供了@Before,@AfterReturning,@AfterThrowing,@After,@Around等大量的Annotation,用于定义功能丰富增强处理。
而EJB提供的拦截器机制只能算是一种轻量级的AOP实现,功能比较有限。
(二)相同点
均使用@AroundInvoke修饰拦截方法,方法中定义的就是分布于多个模块中,具有横切性质的通用处理代码。
三.使用方法
(一)定义一个拦截器
首先定义一个拦截器类,并用@AroundInvoke修饰其中的方法,这个方法将会在SessionBean的多个方法被调用时“切入”。
import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; public class MyInterceptor { @AroundInvoke public Object log(InvocationContext ctx) throws Exception { long start=System.currentTimeMillis(); System.out.println("----拦截器运行开始----"); try { Object rvt = ctx.proceed(); return rvt; } catch (Exception e) { System.out.println("----拦截器运行出错----"); throw e; } finally { long time = System.currentTimeMillis() - start; System.out.println("----拦截器运行结束----"); System.out.println("拦截器运行用时:" + time + "ms"); } } }
可以看出,这个拦截器不需要实现任何接口,或继承什么基类,只要用@AroundInvoke Annotation标记该拦截器类的方法就可以。
需要指出的是,@AroundInvoke修饰的方法必须满足如下格式:
public Object ****(InvocatonContext cxt) throws Exception
形参InvocatonContext 对象中,包含了被调用方法的详细信息,如:
1.Map<String,Object> getContextData():返回一个Map对象,该Map对象里封装了本次调用或生命周期回调相关上下文信息。
2.Method getMethod():获取被拦截的方法
3.Object[] getParameter();获取被拦截的业务方法的实际参数。
4.Object getRarget();获取被拦截的Session Bean实例
5.Object proceed():调用InvocationContext的该方法时,就是回调拦截方法,执行被拦截方法。
6.void setParameters(Object[] params):修改被拦截的业务方法的实际参数
(二)定义被拦截对象
1.定义SessionBean业务接口并声明3个方法
import javax.ejb.Remote; @Remote public interface HelloWorldBean { String hello1(String name); void hello2(); void exclude(); }
接口中无需使用任何Annotation
只要在Bean实现类中使用@Interceptors来修饰即可
2.定义Bean实现类,并用@Interceptors修饰
@Interceptors是EJB3为依赖注入提供的Annotation ,用于修饰Bean类或业务方法,使用时需要用value属性指明拦截器类的类名。
若修饰某个Bean实现类,则对类中的所有方法均起作用
若修饰某个Bean实现类中的方法,则只对标记的方法起作用。
若用@ExcludeClassInterceptors修饰Bean内的某个业务上,则表示拦截器对该标记方法不起作用
import javax.ejb.Stateless; import javax.interceptor.AroundInvoke; import javax.interceptor.Interceptors; import javax.interceptor.InvocationContext; @Stateless(mappedName = "HelloWorldBeanImpl") @Interceptors(MyInterceptor.class) public class HelloWorldBeanImpl implements HelloWorldBean { public String hello1(String name) { System.out.println("我是被拦截器拦击的方法:hello1"); } public void hello2() { System.out.println("我是被拦截器拦截的方法:hello2"); } public void exclude() { System.out.println("我是被拦截器排除在外的方法:exclude"); } }
相关EJB拦截器的使用文章,请参考《EJB3.0中拦截器的实现》
总结
从上述文章可以看出,EJB3的拦截器是一种轻量级AOP机制,和Spring框架中的AOP如出一辙。
而且使用极为简单,开发者只需要如下步骤即可:
(1)定义一个普通类。如何把它标记为拦截器类呢?只需要使用@AroundInvoke修饰一个具有public Object ****(InvocatonContext cxt) throws Exception签名的方法即可。
(2)在所有被拦截的EJB3的Bean实现类、业务方法上使用@Interceptors修饰
(3)如果想在EJB中某个方法中不使用拦截器,则使用@ExcludeClassInterceptors修饰该方法即可。