设计模式(十七):责任链模式(Chain of Responsibility Pattern)

Published on 2024-04-01 17:50 in 分类: 博客 with 狂盗一枝梅
分类: 博客

一、责任链模式定义

责任链模式的定义如下:

使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。(Avoid coupling the sender of a request to its receiver by givingmore 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.)

责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的处理结果。其流程大体如下所示

责任链模式.drawio

举个例子:我买的一台打印机不知道为什么电脑无法识别,于是我打了官方客服电话询问该怎么办

我:你好,我打印机出了点问题,电脑无法识别这个打印机

客服A:你好,我这边是受理投诉的部门,无法解决该问题,稍后会转接到售后部门,请不要挂机

嘟嘟嘟...

客服B:你好,我这边是售后客服,请问有什么能帮到您?

我:你好,我打印机出了点问题,电脑无法识别这个打印机

客服B:您可能没有正确安装驱动,请到官网下载驱动后再看看是否正常识别。

我:好的,我试试。

在这个过程中,我先打了投诉部门的电话,投诉部门处理不了,则将电话转接到了售后部门,售后部门给了我解决方案,这就是一个责任链模式的经典案例。

二、源码中的责任链模式

1、javax.servlet.FilterChain

再开始研究责任链模式在FilterChain中的使用之前,先看下在SpringBoot中,过滤器我们是怎么使用的。

首先要定义一个过滤器,实现OncePerRequestFilter接口,形式上大体如下所示

@Slf4j
@AllArgsConstructor
public class AdminAuthFilter extends OncePerRequestFilter {

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        //此方法返回false表示需要执行该过滤器逻辑,反之则不需要执行过滤器逻辑
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //过滤器业务逻辑
        
        //最后,进入下一个过滤器
        filterChain.doFilter(request, response);
    }
}

我们都知道,FilterChain(过滤器链)是Java Web中的一个概念,用于按顺序执行一系列过滤器对请求进行处理。它是在Servlet容器中实现的一种机制,用于预处理和后处理请求以及响应。

那么filterChain.doFilter(request, response);这个代码做了什么事情呢?

Undertow是和Tomcat一样,都是一种高性能的Servlet容器,在Undertow中,FilterChain的实现类是io.undertow.servlet.handlers.FilterHandler$FilterChainImpl

doFilter逻辑代码位置:https://github.com/undertow-io/undertow/blob/ddb4aeeb32f7ed58d715124acf1d464fc14b30dd/servlet/src/main/java/io/undertow/servlet/handlers/FilterHandler.java#L104

可以看到,该类维护了一个location成员变量,初始值为0,它的作用是一个“游标”,用于遍历另外一个成员变量filters,最关键的一段代码逻辑如下

image-20240401164412806

每调用一次doFilter方法,location都会自增1,如果filters列表没有到末尾,则从filter列表中取下一个Filter尝试执行doFilter方法,很明显这里使用了责任链模式;如果filters列表遍历完,则执行next.handleRequest。嗯?怎么还有个next.handleRequest方法?

mg1Lb

仔细分析下当前类,FilterChainImpl是一个private修饰的内部类,它在FilterHandler类中,我们看下这个类的定义

image-20240401165133851

这个类很有意思,它本身也是另外一个责任链模式中的一个环节。。。好家伙,这还是大责任链模式+小责任链模式,其类图如下所示

责任链模式1-undertow中的责任链模式1.drawio

END.


#设计模式
目录