从头开始了解学习拦截器、认识责任链模式

本文介绍了拦截器的概念,通过定义拦截器接口并使用JDK动态代理来实现拦截器逻辑。同时,深入探讨了责任链模式,展示了如何在多个拦截器中传递对象,以及在不同角色审批过程中如何运用该模式。最后,给出了代码示例和运行结果。
摘要由CSDN通过智能技术生成

由于动态代理之前介绍过的(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个拦截器(实现上面定义的接口)

拦截器1public 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方法");
    }
}
---------------------------------------
拦截器3public 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即可运行,有问题请留言

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值