拦截器(Interceptor)
拦截器可以监听程序的一个或所有方法。拦截器对方法调用流提供了细粒度控制。可以在无状态会话bean、有状态会话bean 和消息驱动bean 上使用它们。拦截器可以是同一bean 类中的方法或是一个外部类。
拦截器可以监听程序的一个或所有方法。拦截器对方法调用流提供了细粒度控制。可以在无状态会话bean、有状态会话bean 和消息驱动bean 上使用它们。拦截器可以是同一bean 类中的方法或是一个外部类。
下面介绍如何在Session Bean 类中使用外部拦截器类。
HelloChinaBean.java
HelloChinaBean.java
package com.foshanshop.ejb3.impl; 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 "我是佛山人"; } }
如果你只需对某一方法进行拦截,你可以在方法上面定义拦截器,如:
public class HelloChinaBean implements HelloChina,HelloChinaRemote { @Interceptors(HelloInterceptor.class) public String SayHello(String name) { return name +"说:你好!中国."; } }
HelloInterceptor
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
XXX 代表方法名可以任意。javax.interceptor.InvocationContext 封装了客户端所调用业务方法的一些信息。下面是
InvocationContext 的定义:
package javax.interceptor;
public interface InvocationContext {
public Object getTarget( );
public Method getMethod( );
public Object[] getParameters( );
public void setParameters(Object[] newArgs);
public java.util.Map<String, Object> getContextData( );
public Object proceed( ) throws Exception;
}
getTarget( ) 指向被调用的bean 实例
getMethod( ) 指向被拦截的业务方法
getParameters( ) 获取被拦截业务方法的参数
setParameters() 设置被拦截业务方法的参数
getContextData( ) 方法返回一个Map 对象,它在整个方法调用期间都可以被访问到。位于同一方法调用内的不同
拦截器之间可以利用它来传递上下文相关的数据。
在HelloInterceptor 代码中,我们调用了ctx.proceed()方法。如果还有其它拦截器未执行,ctx.proceed()方法内部会
调用后面拦截器的@AroundInvoke 方法,直到后面的拦截器全部执行结束,EJB 容器才会执行被拦截的业务方法。
ctx.proceed()方法必须在拦截器代码中被调用,否则被拦截的业务方法就根本不会被执行。另外如果我们想在被拦
截的业务方法执行结束后再执行一些自定义代码,我们可以在ctx.proceed()执行后方法返回前加入自己的代码,
如:
同一个事务和安全上下文中。用@AroundInvoke 注释指定的方法必须遵守以下格式:
public Object XXX(javax.interceptor.InvocationContext ctx) throws Exception
XXX 代表方法名可以任意。javax.interceptor.InvocationContext 封装了客户端所调用业务方法的一些信息。下面是
InvocationContext 的定义:
package javax.interceptor;
public interface InvocationContext {
public Object getTarget( );
public Method getMethod( );
public Object[] getParameters( );
public void setParameters(Object[] newArgs);
public java.util.Map<String, Object> getContextData( );
public Object proceed( ) throws Exception;
}
getTarget( ) 指向被调用的bean 实例
getMethod( ) 指向被拦截的业务方法
getParameters( ) 获取被拦截业务方法的参数
setParameters() 设置被拦截业务方法的参数
getContextData( ) 方法返回一个Map 对象,它在整个方法调用期间都可以被访问到。位于同一方法调用内的不同
拦截器之间可以利用它来传递上下文相关的数据。
在HelloInterceptor 代码中,我们调用了ctx.proceed()方法。如果还有其它拦截器未执行,ctx.proceed()方法内部会
调用后面拦截器的@AroundInvoke 方法,直到后面的拦截器全部执行结束,EJB 容器才会执行被拦截的业务方法。
ctx.proceed()方法必须在拦截器代码中被调用,否则被拦截的业务方法就根本不会被执行。另外如果我们想在被拦
截的业务方法执行结束后再执行一些自定义代码,我们可以在ctx.proceed()执行后方法返回前加入自己的代码,
如:
@AroundInvoke public Object log(InvocationContext ctx) throws Exception { System.out.println("*** HelloInterceptor intercepting"); long start = System.currentTimeMillis(); try{ Object o = ctx.proceed(); //这里加入你需要执行的代码 return o; }catch (Exception e) { throw e; }finally { long time = System.currentTimeMillis() - start; System.out.println("用时:"+ time + "ms"); } }
将Session Bean 中的一个或多个方法定义为拦截器,只需一个@AroundInvoke 注释就指定了要用作拦截器的方法。
package com.foshanshop.ejb3.impl; 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.AroundInvoke; import javax.interceptor.InvocationContext; @Stateless @Remote ({HelloChinaRemote.class}) @Local(HelloChina.class) public class HelloChinaBean implements HelloChina,HelloChinaRemote { public String SayHello(String name) { return name +"说:你好!中国."; } public String Myname() { return "我是佛山人"; } @AroundInvoke public Object log(InvocationContext ctx) throws Exception { try{ if (ctx.getMethod().getName().equals("SayHello")){ System.out.println("*** HelloChinaBean.SayHello() 已经被调用! *** " ); } if (ctx.getMethod().getName().equals("Myname")){ System.out.println("*** HelloChinaBean.Myname() 已经被调用! *** " ); } return ctx.proceed(); }catch (Exception e) { throw e; } }