拦截器的概念大家肯定不陌生。从字面而言,拦截你行为,至于如何获取你的行为,那就是拦截器的原理——通过反射获取你下一步的操作。
在面向切面编程中,其实就是在你的方法之前或之后调用方法。比如动态代理就是拦截器的实现的代表。
既然如此,想想使用动态代理的例子,都可以使用拦截器。比如权限,事务,以及日志。在调用具体的业务之前或之后,打印一条日志到日志文件和数据库中。而不是每次都在代码中重复写代码。
日志操作,在上篇博客中我们已经提到,上篇博客我们是使用spring来配置aop,而这篇博客跟大家介绍EJB拦截器。其实,拦截器的原来了解后,至于EJB也好,Struts2也好,这只是具体的形式实现,来加强对拦截器的理解。
在EJB3.0中,拦截器可以作为一个外部类而言,当然也可以作为某类中一个方法。
第一种:作为外部类而言:
在EJB项目中:
package ejb; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; public class HelloInterceptor { //使用@AroundInvoke注释,指定了要做拦截器的方法。 //使用此注释的格式必须遵守public Object XXX(InvocationContext ctx)throws Exception @AroundInvoke public Object log(InvocationContext ctx) throws Exception{ System.out.println("interceptor....."); System.out.println("此时执行的方法:"+ctx.getMethod().getName()); Object obj=ctx.proceed(); System.out.println(ctx.getMethod().getName()+"已经执行成功。"); return obj; } }其中注释AroundInvoke说明此是作为拦截器的方法,将会调用此拦截器的此方法。
package ejb; public interface HelloChinaRemote { public String sayHello(String name); public String Myname(); }具体的实现:
package ejb; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.interceptor.Interceptors; @Stateless @Remote @Interceptors({HelloInterceptor.class}) public class HelloChinaBean implements HelloChinaRemote { public String Myname() { // TODO Auto-generated method stub return "我是釜山人"; } public String sayHello(String name) { // TODO Auto-generated method stub return name+"我是来自中国。"; } }客户端新建java项目,把ejb项目引入或这把接口打包。因为客户端需要知道EJB端的接口。
package ejb; import javax.naming.InitialContext; public class HelloManagerClient { public static void main(String[] args) throws Exception{ InitialContext context=new InitialContext(); HelloChinaRemote hello=(HelloChinaRemote)context.lookup("HelloChinaBean/remote"); hello.Myname(); hello.sayHello("test"); } }记得在客户端src下添加jndi.properties文件:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.provider.url=localhost java.naming.factory.url.pkgs=org.jboss.naming测试结果如下:
13:09:01,312 INFO [STDOUT] interceptor..... 13:09:01,312 INFO [STDOUT] 此时执行的方法:Myname 13:09:01,312 INFO [STDOUT] Myname已经执行成功。 13:09:01,323 INFO [STDOUT] interceptor..... 13:09:01,323 INFO [STDOUT] 此时执行的方法:sayHello 13:09:01,323 INFO [STDOUT] sayHello已经执行成功。第二种:某类中某方法
不必写外部类:HelloInterceptor
而是直接在我们sessionbean中写方法:【为了方便我们测试,我们又新建一个类】
package ejb; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.interceptor.AroundInvoke; import javax.interceptor.Interceptors; import javax.interceptor.InvocationContext; @Stateless @Remote public class HelloChinaBeanInner implements HelloChinaRemote { public String Myname() { // TODO Auto-generated method stub return "我是釜山人"; } public String sayHello(String name) { // TODO Auto-generated method stub return name+"我是来自中国。"; } //使用@AroundInvoke注释,指定了要做拦截器的方法。 //使用此注释的格式必须遵守public Object XXX(InvocationContext ctx)throws Exception @AroundInvoke public Object log(InvocationContext ctx) throws Exception{ System.out.println("interceptor....."); System.out.println("此时执行的方法:"+ctx.getMethod().getName()); Object obj=ctx.proceed(); System.out.println(ctx.getMethod().getName()+"已经执行成功。"); return obj; } }客户端,我们就不用写了,如上述。【若是按照上述测试,记得更改客户端的jndi名字】
至于第一种方式和第二种方式区别。
第一种方式:虽然多写一个外部类,但是耦合度弱。
第二种方式:在同一个类中,耦合度关联强。