一、拦截器的理解
学习拦截器之前需要对动态代理和反射有一定的基础。
官方说法:
java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。
简单来说,就是拦截器可以提供一个在方法调用之前的方法,调用之后的方法,方便我们在方法执行的前后做拦截判或其他业务处理。
二、Jdk动态代理+拦截器
创建一个普通接口:HelloWorld.java
1 package com.xfwl.proxy.jdk; 2 3 public interface HelloWorld { 4 public void sayHelloWorld(); 5 }
创建一个上面皆接口的实现子类:HelloWorldImpl.java
1 package com.xfwl.proxy.jdk; 2 3 public class HelloWorldImpl implements HelloWorld { 4 5 public void sayHelloWorld() { 6 System.out.println("Hello World!"); 7 } 8 }
创建一个拦截器的接口:Interceptor.java
package com.xfwl.interceptor; import java.lang.reflect.Method; /** * 定义一个拦截器接口 * @function * @author 小风微凉 * @time 2018-7-9 下午2:20:35 */ public interface Interceptor { /** * 拦截器-真实方法调用之前before * @param proxy 代理对象 * @param target 真实对象 * @param method 真实方法 * @param args 运行参数 * @return 返回boolean false则执行around(),true则不执行around() */ public boolean before(Object proxy,Object target,Method method,Object[] args); /** * before()返回 false则执行around(),true则不执行around() * @param proxy 代理对象 * @param target 真实对象 * @param method 真实方法 * @param args 运行参数 */ public void around(Object proxy,Object target,Method method,Object[] args); /** * before/around执行之后执行after() * @param proxy 代理对象 * @param target 真实对象 * @param method 真实方法 * @param args 运行参数 */ public void after(Object proxy,Object target,Method method,Object[] args); }
创建上面拦截器接口的实现子类:MyInterceptor.java
1 package com.xfwl.interceptor; 2 3 import java.lang.reflect.Method; 4 /** 5 * 拦截器实现子类 6 * @function 理解拦截器之前需要理解动态代理+反射机制 7 * @author 小风微凉 8 * @time 2018-7-9 下午2:25:34 9 */ 10 public class MyInterceptor implements Interceptor { 11 12 @Override 13 public boolean before(Object proxy, Object target, Method method,Object[] args) { 14 System.out.println("反射方法前逻辑!"); 15 return false; 16 } 17 18 @Override 19 public void around(Object proxy, Object target, Method method, Object[] args) { 20 System.out.println("取代了被代理对象的方法!"); 21 } 22 23 @Override 24 public void after(Object proxy, Object target, Method method, Object[] args) { 25 System.out.println("反射方法后逻辑!"); 26 } 27 }
创建一个动态代理类:InterceptorJdkProxy.java
1 package com.xfwl.interceptor; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 /** 7 * JDK动态代理实现类 8 * @function 在代理类中嵌入拦截器,关键点还是动态代理 9 * @author 小风微凉 10 * @time 2018-7-9 下午2:29:21 11 */ 12 public class InterceptorJdkProxy implements InvocationHandler { 13 //真实对象 14 private Object target=null; 15 //拦截器全称 16 private String interceptorClass=null; 17 //动态代理类构造器 18 public InterceptorJdkProxy(){} 19 public InterceptorJdkProxy(Object target,String interceptorClass){ 20 this.interceptorClass=interceptorClass; 21 this.target=target; 22 } 23 /** 24 * 给真实独享绑定代理对象 25 * @param target 真实对象 26 * @param interceptorClass 拦截器的全称 27 * @return 代理对象【占位】 28 */ 29 public Object bind(Object target,String interceptorClass){ 30 return Proxy.newProxyInstance( 31 target.getClass().getClassLoader(),//真实对象的类加载器 32 target.getClass().getInterfaces(), //真实对象的实现接口 33 new InterceptorJdkProxy(target, interceptorClass)//实现了InvocationHandler接口的实现类,一般为当前代理类对象 34 ); 35 } 36 /** 37 * 通过代理对象调用方法,首先进入这个方法 38 * @param proxy 代理对象 39 * @param method 方法 40 * @param args 运行参数 41 * @return 42 */ 43 @Override 44 public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { 45 //判断当前代理是否使用了拦截器 46 if(interceptorClass==null){ 47 //没有拦截器,则直接执行真实对象的方法 48 return method.invoke(this.target, args); 49 } 50 Object result=null; 51 //通过反射拿到拦截器对象 52 Interceptor interceptor =(Interceptor)Class.forName(interceptorClass).newInstance(); 53 //调用前置方法 54 if(interceptor.before(proxy, args, method, args)){ 55 //反射真实对象原有的方法 56 result=method.invoke(target, args); 57 }else{ 58 //返回false,执行around方法 59 interceptor.around(proxy, args, method, args); 60 } 61 //调用后置方法 62 interceptor.after(proxy, args, method, args); 63 return result; 64 } 65 }
创建一个测试类:TestInterceptor.java.
1 package com.xfwl.interceptor; 2 3 import com.xfwl.proxy.jdk.HelloWorld; 4 import com.xfwl.proxy.jdk.HelloWorldImpl; 5 6 /** 7 * 拦截器测试 8 * @function 测试一下拦截器是如何起作用的, 9 * @author 小风微凉 10 * @time 2018-7-9 下午2:19:15 11 */ 12 public class TestInterceptor { 13 14 /** 15 * @param args 16 */ 17 public static void main(String[] args) { 18 //拿到代理对象,并绑定真实对象 19 HelloWorld proxy=(HelloWorld) new InterceptorJdkProxy().bind( 20 new HelloWorldImpl(), 21 "com.xfwl.interceptor.MyInterceptor" 22 ); 23 //执行代理逻辑 24 proxy.sayHelloWorld(); 25 26 } 27 28 }
测试结果:
运行条件【1】:
1 @Override 2 public boolean before(Object proxy, Object target, Method method,Object[] args) { 3 System.out.println("反射方法前逻辑!"); 4 return false; 5 }
运行结果:
反射方法前逻辑!
取代了被代理对象的方法!
反射方法后逻辑!
运行条件【2】:
1 @Override 2 public boolean before(Object proxy, Object target, Method method,Object[] args) { 3 System.out.println("反射方法前逻辑!"); 4 return true; 5 }
运行结果:
反射方法前逻辑! Hello World! 反射方法后逻辑!
从上面可以看出,拦截器生效了!