拦截器可以拦截Session Bean和Message-driven Bean的方法调用或生命周期事件。拦截器用于封装应用的公用行为,使这些行为与业务逻辑分离。拦截器可以使同一bean类中的方法或者是一个外部类。
比如
HelloChinaBean
import com.foshanshop.ejb3.HelloChina;
import com.foshanshop.ejb3.HelloChinaRemote;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
@Stateless
@Remote (HelloChinaRemote.class)
@Local(HelloChina.class)
@Interceptors(HelloInterceptor.class)
public class HelloChinaBean implements HelloChina,HelloChinaRemote {
public String SayHello(String name) {
return name +"说:你好!中国.";
}
public String Myname() {
return "我是佛山人";
}
}
@Interceptors注释指定一个或多个在外部类中定义的拦截器,多个拦截器用逗号隔开。
上面拦截器HelloInterceptor对HelloChinaBean的所有方法进行拦截。如果你只需对某一方法拦截,你可以在方法上面定义拦截器,如:
@Interceptors(HelloInterceptor.class)
public class HelloChinaBean implements HelloChina,HelloChinaRemote {
public String SayHello(String name) {
return name +"说:你好!中国.";
}
}
拦截器HelloInterceptor.java
package com.foshanshop.ejb3.impl;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
public class HelloInterceptor {
@AroundInvoke
public Object log(InvocationContext ctx) throws Exception {
System.out.println("*** HelloInterceptor intercepting");
long start = System.currentTimeMillis();
try{
if (ctx.getMethod().getName().equals("SayHello")){
System.out.println("*** SayHello 已经被调用! *** " );
}
if (ctx.getMethod().getName().equals("Myname")){
System.out.println("*** Myname 已经被调用! *** " );
}
return ctx.proceed();
}catch (Exception e) {
throw e;
}finally {
long time = System.currentTimeMillis() - start;
System.out.println("用时:"+ time + "ms");
}
}
}
@AroundInvoke注释指定了要用作拦截器的方法,拦截器方法与被拦截的业务方法执行同一个java调用堆栈、同一个事务和安全上下文中。用@AroundInvoke注释指定的方法必须遵守以下格式:
public Object XXX(javax.interceptor.InvocationContext ctx) throws Exception
下面是javax.interceptor.InvocationContext封装了客户端所调用业务方法的一些信息。
InvocationContext定义:
package javax.interceptor;
public interface InvocationContext{
public Object getTarget();
public Method getMethod();
public Ojbect[] getParameters();
public void setParameters(Object[] newArgs);
public java.util.Map<String, Ojbect> getContextData();
public Object proceed() throws Exception;
}
getTarget() 指向被调用的bean实例
getMethod() 指向被拦截的业务方法
getParameters() 获取被拦截业务方法的参数
setParameters() 设置被拦截业务方法的参数
getContextData() 返回一个Map对象,它在整个方法调用期间都可以被访问到。位于同一个方法调用内的不同拦截器之间可以利用它来传递上下文相关的数据。
在HelloInterceptor代码中,我们调用了ctx.proceed()方法。如果还有其他拦截器未执行,ctx.proceed()方法内部会调用后面拦截器的@AroundInvoke方法。直到后面的拦截器全部执行结束,EJB容器才会执行被拦截的业务方法。另外如果我们想在被拦截的业务方法执行结束后再执行一些自定义的代码,我们可以在ctx.proceed()执行后方法返回前加入自己的代码。
如
@AroundInvoke
public Object log(InvocationContext ctx) throws Exception {
System.out.println("*** HelloInterceptor intercepting");
long start = System.currentTimeMillis();
try{
if (ctx.getMethod().getName().equals("SayHello")){
System.out.println("*** SayHello 已经被调用! *** " );
}
if (ctx.getMethod().getName().equals("Myname")){
System.out.println("*** Myname 已经被调用! *** " );
}
Object o= ctx.proceed();
//insert your code
return o;
}catch (Exception e) {
throw e;
}finally {
long time = System.currentTimeMillis() - start;
System.out.println("用时:"+ time + "ms");
}
}
由于拦截器和被拦截的bean方法同处于一个java调用堆栈中,如果你希望终止方法执行,可以抛出异常。业务方法也告结束。