由于动态代理之前介绍过的(JDK动态代理、CGLIB动态代理)在实际开发一般比较难理解,程序设计者会设计一个拦截器接口供考法这使用,开发者只需知道拦截器接口的方法,含义和作用即可,无需 知道动态代理是怎么实现的,用JDK动态代理来实现一个拦截器的逻辑,为此先定义拦截器接口,代码如下:
定义拦截器接口
/**
* @author AmVilCres
* <p>
* 该接口定义了3个方法:before、around、after
* <li>3个方法的参数为:proxy代理对象、target真实的对象、method方法、args运行方法参数</li>
* <li>before方法返回boolean值,它在真实对象前调用。当返回true时,则反射真实对象的方法;当返回false时,则调用around方法</li>
* <li>在反射真实对象方法或者around方法执行之后,调用after方法</li>
* </p>
*/
public interface Interceptor {
public boolean before(Object proxy, Object target, Method method, Object[] args);
public void around(Object proxy, Object target, Method method, Object[] args);
public void after(Object proxy, Object target, Method method, Object[] args);
}
接口的上面注释已经写得很明白了,相信大家都能看懂,接下来写一个接口的实现类:
public class MyInterceptor implements Interceptor {
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.err.println("反射方法前逻辑");
return false; //不反射被代理对象的原有方法
}
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("取代了被代理对象的方法");
}
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("反射方法后逻辑");
}
}
使用JDK动态代理,就可以去实现这些方法在适当时调用的逻辑了,JDK动态代理中使用拦截器代码如下:
public class InterceptorJdkProxy implements InvocationHandler{
private Object target; //真实对象
private String interceptorClass; // 拦截器全限定名
public InterceptorJdkProxy(Object target,String interceptorClass) {
this.target = target;
this.interceptorClass = interceptorClass;
}
/**
* 绑定委托对象并返回一个 【代理占位】
*
* @param target 真实的对象
* @return 代理对象【占位】
* */
public static Object bind(Object target, String interceptorClass) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new InterceptorJdkProxy(target, interceptorClass));
}
/**
* 通过代理对象调用方法,首先进入的是这个方法
*
* @param proxy 代理对象
* @param method 被调用的方法
* @param args 方法的参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(interceptorClass == null)
return method.invoke(target, args);
Object res = null;
//通过反射生成拦截器
Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();
if(interceptor.before(proxy, target, method, args))
res = method.invoke(target, args); //反射原有对象方法
else {
interceptor.around(proxy, target, method, args);
}
interceptor.after(proxy, target, method, args);
return res;
}
}
代码说明:这里有两个属性,一个是target,它是真实的对象;另一个是字符串interceptorClass,它是一个类的全限定名
执行步骤:
1. 在bind方法中用JDK动态代理绑定一个对象,然后返回代理对象
2. 如果没有设置拦截器,则直接反射真实对象的方法,然后结束,否则进行第3步,
3. 通过反射生成拦截器,并准备使用它
4. 调用拦截器的before方法,如果返回true,反射原来的方法,否则运行拦截器的around方法
5. 调用拦截的after方法
6. 返回结果
拦截器工作流程图:
测试代码:
public class TestInterceptorJdkProxy {
public static void main(String[] args) {
// "com.avc.interceptor.MyInterceptor"我定义的为拦截器的全限定名
HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), "com.avc.interceptor.MyInterceptor");
proxy.sayHello();
}
}
运行结果:
责任链模式
上面讨论了设计者可能会用拦截器去代替动态代理,然后将接口提供给开发者,从而简化开发者难度,但是拦截器可能有多个。举个栗子, 某人需要请假一周,如果把请假申请单看成一个对象,那么他需要经过项目经理、部门经理、人事等多个角色的审批,每个角色都有机会通过拦截这个申请进行审批或者修改。这个时候就要考虑提供这3个角色的处理逻辑,所以需要提供3个拦截器,而传递的则是请假申请单 如图:
当一个对象在一条链被多个拦截器拦截处理(拦截器也可以选择不拦截他)时,就把这样的设计模式称为责任链模式,它用于一个对象在多个角色中传递的场景。还是刚才的例子,申请单走到项目经理那,可能吧时间改为5天,从而影响了后面的审批,后面的审批都要根据前面的结果进行。这个时候考虑用层层代理来实现,就是当申请单(target)走到项目经理处,使用第一个动态代理proxy1,走到部门经理处,部门经理会得到一个在项目经理的代理proxy1基础上生成的proxy2,当走到人事的时候,会在proxy2的及出生成proxy3,如果还有其他角色,以此类推,下图描述会更清晰:
定义3个拦截器(实现上面定义的接口)
拦截器1:
public class Interceptor1 implements Interceptor {
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器 1 的 before方法");
return true;
}
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器 1 的 around方法");
}
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器 1 的 after方法");
}
}
----------------------------------
拦截器2:
public class Interceptor2 implements Interceptor {
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器 2 的 before方法");
return true;
}
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器 2 的 around方法");
}
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器 2 的 after方法");
}
}
---------------------------------------
拦截器3:
public class Interceptor3 implements Interceptor {
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器 3 的 before方法");
return true;
}
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器 3 的 around方法");
}
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器 3 的 after方法");
}
}
测试类:
public class LinkInterceptorTest {
public static void main(String[] args) {
HelloWorld proxy1 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), "com.avc.interceptor.link.Interceptor1");
HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(proxy1, "com.avc.interceptor.link.Interceptor2");
HelloWorld proxy3 = (HelloWorld) InterceptorJdkProxy.bind(proxy2, "com.avc.interceptor.link.Interceptor3");
proxy3.sayHello();
}
}
运行结果:
可以通过改变before方法的返回值,从而得到不同的结果!
代码下载:上述代码的源码,导入eclipse即可运行,有问题请留言