简述
前面我们了解了动态代理以及JDK动态代理技术,由于动态代理比较难理解,程序设计者通常会设计一个拦截器接口给开发人员使用,开发人员只需要实现该接口并像应用注册即可。
SpringMvc中的拦截器就是这样,实现org.springframework.web.servlet.HandlerInterceptor接口,然后向配置文件中去注册该实现类。
代码案例
本案例所有代码可到动态代理之拦截器中去下载
【拦截器接口】
//拦截器接口import java.lang.reflect.Method; public interface Interceptor { boolean before(Object proxy, Object target, Method method, Object[] args); void around(Object proxy, Object target, Method method, Object[] args); void after(Object proxy, Object target, Method method, Object[] args); }
【拦截器实现类】
//拦截器实现类import java.lang.reflect.Method;public class MyInterceptor implements Interceptor { @Override public boolean before(Object proxy, Object target, Method method, Object[] args) { System.err.println("反射方法前逻辑 --- 判断用户是否处于登录状态 --- 用户未登录,操作拦截"); return false;//不反射被代理对象原有方法,这里true或false根据开发人员需求自定义 } @Override public void around(Object proxy, Object target, Method method, Object[] args) { System.err.println("取代了被代理对象的方法 --- 页面转发到登录页面"); } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.err.println("反射方法后的逻辑 --- 记录本次异常操作"); } }
【动态代理逻辑】
//动态代理逻辑import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class InterceptorJdkProxy implements InvocationHandler { private Object target;//真实对象 private String interceptorClass = null;//拦截器全限定名 public InterceptorJdkProxy(Object target, String interceptorClass) { this.target = target; this.interceptorClass = interceptorClass; } /** * 绑定委托对象,并返回一个【代理占位】 * @param target 真实对象 * @param interceptorClass * @return 代理对象【占位】 */ public static Object bind(Object target, String interceptorClass){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InterceptorJdkProxy(target, interceptorClass)); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(interceptorClass == null){ //代表没有设置拦截器,直接反射原有方法 return method.invoke(target, args); } Object result = null; //通过反射生成拦截器 Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance(); //调用前置方法 if(interceptor.before(proxy, target, method, args)){ result = method.invoke(target, args); }else { interceptor.around(proxy, target, method, args); } //调用后置方法 interceptor.after(proxy, target, method, args); return result; } }
【测试】
//测试import com.bpf.chapter2.proxy.jdkProxy.HelloWorld;import com.bpf.chapter2.proxy.jdkProxy.HelloWorldImpl;public class TestInterceptor { public static void main(String[] args) { //注册拦截器 HelloWorld proxy1 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), "com.bpf.chapter2.proxy.interceptor.MyInterceptor"); //不注册拦截器 HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), null); proxy1.sayHelloWorld(); /* 结果 反射方法前逻辑 --- 判断用户是否处于登录状态 --- 用户未登录,操作拦截 取代了被代理对象的方法 --- 页面转发到登录页面 反射方法后的逻辑 --- 记录本次异常操作 */ proxy2.sayHelloWorld(); /* 结果 hello world! */ } }
作者:写代码的白大侠
链接:https://www.jianshu.com/p/d9136d25fdfc