What

  • 定义

    Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it. 将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。

上面是GoF的定义,在实际的开发中,也存在对这个模式的变体,那就是请求不会中途终止传递,而是会被所有的处理器都处理一遍,或者直到某个处理器不处理了为止等。

  • 应用

职责链模式常用在框架的开发中,为框架提供扩展点,让框架的使用者在不修改框架源码的情况下,基于扩展点添加新的功能,这也体现了对修改关闭对扩展开发的设计原则。实际上,更具体点来说,职责链模式最常用来开发框架的过滤器和拦截器。

  • 优点
  1. 降低耦合度。它将请求的发送者和接收者解耦;
  2. 简化了对象。使得对象不需要知道链的结构;
  3. 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任;
  4. 增加新的请求处理类很方便。
  • 缺点
  1. 不能保证请求一定被接收;
  2. 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用;
  3. 可能不容易观察运行时的特征,有碍于除错。
  • 使用场景
  1. 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定;
  2. 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;
  3. 可动态指定一组对象处理请求。

How

数组式

  1. /**
  2. * 数组式实现
  3. * <p>
  4. * 沿着处理链,如果某个处理器能处理该请求,就不继续往下传递;如果不能处理,则交由后面的处理器来处理
  5. *
  6. * @author yiy
  7. * @date 12/22/2021
  8. */
  9. public class ArrayWay {
  10. public static void main(String[] args) {
  11. HandlerChain chain = new HandlerChain();
  12. chain.addHandler(new HandlerA());
  13. chain.addHandler(new HandlerB());
  14. chain.triggerHandle();
  15. }
  16. }
  17. /**
  18. * 处理器接口
  19. */
  20. interface IHandler {
  21. /**
  22. * 处理逻辑
  23. *
  24. * @return true:能够处理,中断链路无需继续向后传递;false:不能处理,继续向后传递
  25. */
  26. boolean doHandle();
  27. }
  28. /**
  29. * 处理器A
  30. */
  31. class HandlerA implements IHandler {
  32. @Override
  33. public boolean doHandle() {
  34. //具体处理逻辑...
  35. System.out.println("处理器A无法处理,传递至下一个处理器!");
  36. return false;
  37. }
  38. }
  39. /**
  40. * 处理器B
  41. */
  42. class HandlerB implements IHandler {
  43. @Override
  44. public boolean doHandle() {
  45. //具体处理逻辑...
  46. System.out.println("处理器B能处理,中断处理链路!");
  47. return true;
  48. }
  49. }
  50. /**
  51. * 处理器链
  52. */
  53. class HandlerChain {
  54. /**
  55. * 处理器
  56. */
  57. private List<IHandler> handlerList = new ArrayList<>();
  58. /**
  59. * 添加处理器到处理器链中
  60. *
  61. * @param handler 处理器
  62. */
  63. public void addHandler(IHandler handler) {
  64. this.handlerList.add(handler);
  65. }
  66. /**
  67. * 触发处理链
  68. */
  69. public void triggerHandle() {
  70. for (IHandler handler : handlerList) {
  71. //执行处理器,并判断是否继续向下处理
  72. if (handler.doHandle()) {
  73. //中断链路
  74. break;
  75. }
  76. }
  77. }
  78. }

链表式

  1. /**
  2. * 链表式实现
  3. * 单向链表
  4. *
  5. * @author yiy
  6. * @date 12/22/2021
  7. */
  8. public class LinkedListWay {
  9. public static void main(String[] args) {
  10. HandlerChain chain = new HandlerChain();
  11. chain.addHandler(new HandlerC());
  12. chain.addHandler(new HandlerD());
  13. chain.triggerHandle();
  14. }
  15. }
  16. /**
  17. * 处理器抽象父类
  18. */
  19. abstract class Handler {
  20. /**
  21. * 下一个处理器
  22. */
  23. protected Handler successor = null;
  24. public void setSuccessor(Handler successor) {
  25. this.successor = successor;
  26. }
  27. /**
  28. * 头部处理器触发整条链的入口
  29. */
  30. public final void handle() {
  31. boolean handled = doHandle();
  32. if (successor != null && !handled) {
  33. //通知下一个处理器处理
  34. successor.handle();
  35. }
  36. }
  37. /**
  38. * 处理逻辑
  39. *
  40. * @return true:能够处理,中断链路无需继续向后传递;false:不能处理,继续向后传递
  41. */
  42. protected abstract boolean doHandle();
  43. }
  44. /**
  45. * 处理器C
  46. */
  47. class HandlerC extends Handler {
  48. @Override
  49. protected boolean doHandle() {
  50. //具体处理逻辑...
  51. System.out.println("处理器C无法处理,传递至下一个处理器!");
  52. return false;
  53. }
  54. }
  55. /**
  56. * 处理器D
  57. */
  58. class HandlerD extends Handler {
  59. @Override
  60. protected boolean doHandle() {
  61. //具体处理逻辑...
  62. System.out.println("处理器D能处理,中断处理链路!");
  63. return false;
  64. }
  65. }
  66. /**
  67. * 处理器链
  68. */
  69. class HandlerChain {
  70. private Handler head = null;
  71. private Handler tail = null;
  72. /**
  73. * 添加处理器到处理器链中
  74. *
  75. * @param handler 处理器
  76. */
  77. public void addHandler(Handler handler) {
  78. handler.setSuccessor(null);
  79. //处理器链为空,将处理器链的头尾都置为当前添加的处理器
  80. if (head == null) {
  81. head = handler;
  82. tail = handler;
  83. return;
  84. }
  85. //处理器链不为空
  86. // 将尾部处理器指向当前添加的处理器
  87. tail.setSuccessor(handler);
  88. //将当前添加的处理器设置为尾部处理器
  89. tail = handler;
  90. }
  91. /**
  92. * 触发链路
  93. */
  94. public void triggerHandle() {
  95. if (head != null) {
  96. head.handle();
  97. }
  98. }
  99. }

应用案例

过滤器

  • Servlet Filter 中就是数组式的变种实现

十分精妙,通过处理链中递归调用处理器,实现了在doHandle方法中,支持双向拦截,当前处理器既能拦截执行下一个处理器执行前的数据,又能拦截下一个处理器执行后的数据,这样的实现方式是参考的Servlet Filter

  • 注意:这里稍微变化了一些,是将数据在整个链路中都处理一遍 ```java /**
    • 过滤器 *
    • @author yiy
    • @date 12/22/2021
    • @since Servlet Filter
    • 通过递归实现的过滤器间的调用,
    • 十分精妙,实现了在doFilter方法中,支持双向拦截,既能拦截执行过滤器执行前的数据,又能拦截过滤器执行后的数据
    • 注意:这里稍微变化了一些,是将数据在整个链路中都过滤一遍 */ public class ServletFilterApply { public static void main(String[] args) { FilterChain chain = new FilterChain(); chain.addFilter(new FilterA()); chain.addFilter(new FilterB()); Object data = new Object(); chain.doFilter(data); } }

/**

  • 过滤器接口 *
  • @since javax.servlet.Filter */ interface IFilter {

    /**

    • 过滤逻辑 *
    • @param data 被过滤的数据
    • @param chain 过滤器链 */ void doFilter(Object data, FilterChain chain); }

/**

  • 过滤器A */ class FilterA implements IFilter { @Override public void doFilter(Object data, FilterChain chain) {

     //本过滤器具体过滤逻辑...
    
     chain.doFilter(data);    //执行下一个过滤器
    
     //下一个过滤器完成后的过滤增强...
    

    } }

/**

  • 过滤器B */ class FilterB implements IFilter { @Override public void doFilter(Object data, FilterChain chain) {

     //具体过滤逻辑...
    

    } }

/**

  • 过滤链 *
  • @since org.apache.catalina.core.ApplicationFilterChain / class FilterChain { /*

    • 当前执行到那个过滤器了 */ private int pos = 0;

      /**

    • 过滤器链 */ private List filterList = new ArrayList<>();

      /**

    • 添加过滤器到过滤器链中 *
    • @param filter 过滤器 */ public void addFilter(IFilter filter) { this.filterList.add(filter); }

      /**

    • 执行链中的过滤器 *
    • @param data 过滤的数据 */ public void doFilter(Object data) { IFilter filter = filterList.get(pos++); //执行过滤器 filter.doFilter(data, this); } } ``` 说明:我看Servlet Filter源码中,将FilterChain也抽象出了一个接口,解耦更彻底。

拦截器

  • SpringMVC Interceptor 中就是数组式的变种实现,拦截链示意图如下:

职责链模式🌟 - 图1

/**
 * 拦截器
 * <p>
 * springMVC拦截器就是数组式的变种实现
 * 执行拦截链,只要其中有一个拦截器没通过(返回false),就中断拦截链
 *
 * @author yiy
 * @date 12/23/2021
 * @since spring Interceptor
 */
public class SpringInterceptorApply {
    public static void main(String[] args) {
        InterceptorChain chain = new InterceptorChain();
        chain.addInterceptor(new InterceptorA());
        chain.addInterceptor(new InterceptorB());
        chain.addInterceptor(new InterceptorC());
        if (!chain.applyPreHandle()) {
            return;
        }
        System.out.println("===========执行被拦截的逻辑!=============");
        chain.applyPostHandle();
        chain.triggerAfterCompletion();
    }
}

/**
 * 拦截器接口
 *
 * @since org.springframework.web.servlet.HandlerInterceptor
 */
interface IInterceptor {

    /**
     * 前置函数
     * 可校验当前拦截器是否通过
     *
     * @return true:通过,校验下一个拦截器
     */
    boolean preHandle();

    /**
     * 后置函数
     * 在所有preHandle函数通过后统一执行
     */
    void postHandle();


    /**
     * 终函数
     * 无论是否校验通过,始终会执行,可用于做资源清理等操作(正常处理时机是在postHandle之后)
     */
    void afterCompletion();

}

/**
 * 拦截器A
 */
class InterceptorA implements IInterceptor {
    @Override
    public boolean preHandle() {
        //校验是否通过拦截的逻辑
        System.out.println("拦截器A前置函数!");
        return true;
    }

    @Override
    public void postHandle() {
        //通过拦截后,具体处理逻辑
        System.out.println("拦截器A后置函数!");
    }

    @Override
    public void afterCompletion() {
        //始终处理逻辑
        System.out.println("拦截器A资源释放!");
    }
}

/**
 * 拦截器B
 */
class InterceptorB implements IInterceptor {
    @Override
    public boolean preHandle() {
        //校验是否通过拦截的逻辑
        System.out.println("拦截器B前置函数!");
        return true;
    }

    @Override
    public void postHandle() {
        //通过拦截后,具体处理逻辑
        System.out.println("拦截器B后置函数!");
    }

    @Override
    public void afterCompletion() {
        //始终处理逻辑
        System.out.println("拦截器B资源释放!");
    }
}

/**
 * 拦截器C
 */
class InterceptorC implements IInterceptor {
    @Override
    public boolean preHandle() {
        //校验是否通过拦截的逻辑
        System.out.println("拦截器C前置函数!");
        return true;
    }

    @Override
    public void postHandle() {
        //通过拦截后,具体处理逻辑
        System.out.println("拦截器C后置函数!");
    }

    @Override
    public void afterCompletion() {
        //始终处理逻辑
        System.out.println("拦截器C资源释放!");
    }
}

/**
 * 拦截器链
 *
 * @since org.springframework.web.servlet.HandlerExecutionChain
 */
class InterceptorChain {
    /**
     * 拦截器
     */
    private List<IInterceptor> interceptorList = new ArrayList<>();

    /**
     * 拦截链中 中断的拦截器的index
     */
    private int interceptorIndex = -1;

    /**
     * 添加拦截器到拦截器链中
     *
     * @param interceptor 拦截器
     */
    public void addInterceptor(IInterceptor interceptor) {
        this.interceptorList.add(interceptor);
    }

    /**
     * 执行拦截逻辑
     *
     * @return false:中断拦截
     */
    public boolean applyPreHandle() {
        for (int i = 0; i < interceptorList.size(); i++) {
            IInterceptor interceptor = interceptorList.get(i);
            //执行拦截器前置函数
            if (!interceptor.preHandle()) {
                triggerAfterCompletion();
                return false;
            }
            //记录中断位置
            interceptorIndex = i;
        }
        return true;
    }

    /**
     * 执行通过拦截后的处理逻辑
     */
    public void applyPostHandle() {
        for (int i = interceptorList.size() - 1; i >= 0; i--) {
            IInterceptor interceptor = this.interceptorList.get(i);
            interceptor.postHandle();
        }
    }

    /**
     * 触发拦截器的最终通知
     */
    public void triggerAfterCompletion() {
        for (int i = this.interceptorIndex; i >= 0; i--) {
            IInterceptor interceptor = this.interceptorList.get(i);
            interceptor.afterCompletion();
        }
    }
}

Why

Filter、Interceptor vs AOP


粒度 应用
Filter 限流就可以在Filter层去做,因为全局都需要限流防止服务被压垮。
Interceptor 用户是否登录权限等可以使用Interceptor做
aop 细粒度到类或者方法的控制使用AOP去做,比如日志 事务 方法级别权限
  • Filter 可以拿到原始的http请求,但是拿不到你请求的控制器和请求控制器中的方法的信息;
  • Interceptor 可以拿到你请求的控制器和方法,也可以拿到请求方法的参数;
  • Aop 可以拿到方法的参数,也可以拿到http请求和响应的对象。