面向对象编程内功心法系列十六(聊一聊责任链模式)

134 阅读6分钟

1.引子

责任链模式,应该说我们都比较熟悉了,比如说servlet规范中的过滤器(filter),再比如说springmvc中的拦截器(interceptor)。

既然大家都这么熟悉了,那么写这篇文章的意义在哪里呢?我们可以尝试思考这么几个问题

  • 抛开框架提供的filter、interceptor,如果说我们自己就是框架开发者,该如何利用责任链模式,提供框架的扩展能力呢?
  • 你知道filter、interceptor底层实现与执行机制吗?换句话说你看过它们的源码吗?
  • 如果在项目中,同时存在filter、interceptor、甚至aop,你知道它们的执行顺序吗?

带着以上几个问题,我将通过这篇文章一并分享给你,期望通过本篇文章,你将获得

  • 如何自己定义实现一个责任链模式
  • 彻底搞清楚filter、interceptor实现原理
  • 不再感到困惑项目中同时存在filter、interceptor、aop

2.案例

2.1.原汁原味责任链模式

从设计模式分类上,责任链模式是一种行为型设计模式,主要解决的是对象之间的交互问题。

通过责任链模式,可以很方便的实现提供代码复用与扩展能力,尤其是开发框架方面,支持用户在不修改框架源码的情况下,非常容易实现根据业务需要,从而扩展框架能力。

这里我用一段话给你描述责任链模式的执行机制,方便你理解,业务场景如下

  • 有一个发送者发送请求
  • 有一个接收者接收请求并处理请求
  • 在发送者与接收者之间,需要一些预处理,比如说认证,授权等,认证与授权之间的事件有依赖关系,必须认证通过后,才会进一步处理授权
  • 那么在发送者与接收者之间,我们可以增加处理器A负责认证、处理器B负责授权,请求只有经过处理器A认证通过后,再进一步通过处理器B授权处理
  • 如果有更多的处理C/D......处理情形类似
  • 你看到了,最终业务请求的处理路径是:发送者发出请求--->处理器A--->处理器B--->......--->接收者处理请求。这就是一条链,也是责任链模式的名称由来

理解了责任链模式,接下来我们来看代码层面该如何实现,需要注意,责任链模式的定义分为两个部分

  • 处理器,通常定义接口,与提供接口实现
  • 处理器链,可以理解为处理器容器

2.1.1.处理器接口

/**
 * 责任链模式,处理器接口
 *
 * @author ThinkPad
 * @version 1.0
 * @date 2021/5/5 20:10
 */
public interface Handler {
​
    /**
     * 处理器接口方法
     * @return
     */
    boolean handle();
}

2.1.2.处理器A

/**
 * 处理器A
 *
 * @author ThinkPad
 * @version 1.0
 * @date 2021/5/5 20:12
 */
public class HandlerA  implements Handler{
​
    /**
     * 处理器接口方法
     *
     * @return
     */
    @Override
    public boolean handle() {
        System.out.println("2.HandlerA...处理执行.");
        return true;
    }
}

2.1.3.处理器B

/**
 * 处理器B
 *
 * @author ThinkPad
 * @version 1.0
 * @date 2021/5/5 20:12
 */
public class HandlerB implements Handler{
​
    /**
     * 处理器接口方法
     *
     * @return
     */
    @Override
    public boolean handle() {
        System.out.println("3.HandlerB...处理执行.");
        return true;
    }
}

2.1.4.处理器链

/**
 * 责任链模式,处理器链
 *
 * @author ThinkPad
 * @version 1.0
 * @date 2021/5/5 20:13
 */
public class HandlerChain {
​
    /**
     * 处理器容器
     */
    private List<Handler> handlerList = new ArrayList<>();
​
    /**
     * 添加处理器
     * @param handler
     */
    public void addHandler(Handler handler){
        handlerList.add(handler);
    }
​
    /**
     * 处理器链传递执行
     * @return
     */
    public void handle(){
        for(Handler handler : handlerList){
            handler.handle();
        }
​
    }
}

2.1.5.使用案例

public static void main(String[] args) {
        // 1.创建处理器链
        HandlerChain handlerChain = new HandlerChain();
​
        // 2.添加处理器
        handlerChain.addHandler(new HandlerA());
        handlerChain.addHandler(new HandlerB());
​
        // 3.处理执行
        System.out.println("1.发送者,发送业务请求.");
        handlerChain.handle();
        System.out.println("4.接收者,完成业务请求处理.");
}
​
#执行结果
1.发送者,发送业务请求.
2.HandlerA...处理执行.
3.HandlerB...处理执行.
4.接收者,完成业务请求处理.
​

2.2.过滤器filter源码分析

filter是servlet规范中很重要的一个组件,现在我们知道了它的实现机制就是责任链模式。那么我们说关注责任链模式,主要关注两个内容

  • 处理器,在过滤器中,Filter即是处理器接口
  • 处理器链,在过滤器中,FilterChain即是处理器链接口

接下来我把关键源码贴出来,并附上相关的注释,相信你理解起来不会有太大的难度

2.2.1.Filter接口

public interface Filter {
   ......省略其它代码......
​
   /*
   *关键方法:我们扩展实现Filter,主要就是重写该方法
   *处理业务逻辑后,再通过FilterChain.doFilter方法,继续执行后续的过滤器
   ***/
    void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException;
​
   ......省略其它代码......
}

2.2.2.FilterChain接口

public interface FilterChain {
    void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}

2.2.3.FilterChain接口实现

public final class ApplicationFilterChain implements FilterChain {
    // 处理器容器
     private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
    // 当前执行哪一个处理器计数
    private int pos = 0;
    // 总处理器数
    private int n = 0;
    
    /*
    *处理器链执行入口方法
    */
     public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
         ......省略其它代码......
         // 调用内部处理方法
          this.internalDoFilter(request, response);
         ......省略其它代码......
     }
    
    /*
    *处理器链内部处理方法
    */
     private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
         // 还没有执行到最后一个过滤器,继续处理执行
         if (this.pos < this.n) {
             // 获取到当前过滤器
              ApplicationFilterConfig filterConfig = this.filters[this.pos++];
              Filter filter = filterConfig.getFilter();
             
             // 过滤器业务处理执行
             filter.doFilter(request, response, this);
             ......省略其它代码......
         }
     }
    
}

2.3.拦截器interceptor源码分析

分析完过滤器Filter、FilterChain源码,不难看出过滤器是标准的责任链模式实现,源码都比较简单。

接下来我们继续分析springmvc提供的拦截器interceptor的源码,同样我把关键源码贴出来,附上注释方便你理解。

2.3.1.HandlerInterceptor处理器接口

springmvc提供的拦截器,将处理器方法分为前置方法(preHandle),与后置方法(postHandle),分别对应了请求的去,来

public interface HandlerInterceptor {
    // 1.controller方法执行前执行
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
​
    // 2.controller方法正常执行后执行
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
​
    // 3.只要进入该拦截器,即可执行
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

2.3.2.HandlerExecutionChain处理器链

public class HandlerExecutionChain {
    
    // 处理器容器
     @Nullable
    private HandlerInterceptor[] interceptors;
    @Nullable
    private List<HandlerInterceptor> interceptorList;
    
    /*
    *添加处理器
    */
    public void addInterceptor(HandlerInterceptor interceptor) {
        this.initInterceptorList().add(interceptor);
    }
    
    /*
    *controller方法执行前执行,前置方法
    */
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 获取处理器容器
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            // 循环依次执行每一个拦截器
            for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
                HandlerInterceptor interceptor = interceptors[i];
                // 执行当前拦截器业务处理
                if (!interceptor.preHandle(request, response, this.handler)) {    // 触发执行afterCompletion
                    this.triggerAfterCompletion(request, response, (Exception)null);
                    return false;
                }
            }
        }
​
        return true;
    }
    
    /*
    *controller方法执行正常执行后执行,后置方法
    */
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for(int i = interceptors.length - 1; i >= 0; --i) {
                HandlerInterceptor interceptor = interceptors[i];
                // 执行当前拦截器业务处理
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
​
    }
    
    
}

2.4.理解filter、interceptor、aop并存

理解了如何自定义实现责任链设计模式,以及分析了Filter、Interceptor的源码后,相信你对责任链模式,已经有一个比较好的掌握了,应该已经get到它的点了。

最后我们再来看一个问题,过滤器Filter、拦截器Interceptor、aop,它们处理的业务场景都非常相似,如果你的项目中,它们同时存在的话,执行顺序是什么样的呢?我们看一个图,你应该可以有答案了

image.png