开个坑补齐设计模式系列笔记, 顺带回顾Spring源码中的设计模式运用…

模式

责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许多个对象有机会处理同一个请求,从而避免请求的发送者与多个接收者之间的耦合, 通常用于请求有多个阶段。该模式通过将这些对象连成一条链,并沿着链传递请求,直到有一个对象处理请求为止。如果链的末端没有对象处理请求,整个请求将被丢弃或默认处理。

未加粗的是责任链复杂程度上去之后可选的角色

  1. 抽象处理者(Handler)
    • 定义:一个接口或抽象类,通常包含一个方法来处理请求以及一个方法来设置下一个处理者。它规定了所有具体处理者都必须实现的基本操作,如处理请求或将请求传递给链中的下一个处理者。
    • 角色接口或抽象类 作为处理链的核心定义,保证每个处理者都具有处理请求的能力。
  • 基础处理者 (Base Handler): 可选
    • 定义:一个接口或部分实现类,它实现了抽象处理者的部分功能或是抽象处理者的拓展。
    • 角色复用和扩展 提供公共的逻辑实现,减少子类的重复代码,增强代码的可复用性。
  1. 具体处理者(ConcreteHandlers)
    • 定义:每个实现类,实现了处理某种请求的逻辑。当它无法处理请求时,会将请求传递给链中的下一个处理者。
    • 角色链的节点实现 实现自己的处理逻辑来参与责任链的请求处理。
  • 链的管理者(Chain Manager):可选
    1. 定义:通常是一个Chain类,实现创建和管理处理者的顺序、组装责任链,并维护链的整体状态。
    2. 角色:构建和维护责任链 确保处理者按照正确的顺序处理请求,同时可以动态地添加、移除或调整链中的处理者。
  • 链的构造器(Chain Creator):可选
    1. 定义:通常是一个工厂类或构造器,负责初始化责任链的结构并返回链的起始处理者。它可以根据具体的业务需求,创建不同类型的责任链。
    2. 角色:生成责任链实例 确保处理者按照正确的顺序处理请求,同时可以动态地添加、移除或调整链中的处理者。
  1. 客户类(Client)
    • 定义:客户类是发起请求的对象,它通常会自行或调用链的构造器创建并设置责任链,然后向责任链的第一个处理者提交请求。
    • 角色责任链的创建者 请求的发起者
责任链模式结构图
责任链模式结构图

场景

公司报销流程就像一条责任链,每个环节都根据条件决定是否继续处理:

  1. 填写申请:你提交的报销单是链上的第一个环节,检查所有必要的字段和金额,确保格式正确。如果不符合条件,它会被退回。
  2. 审批环节:提交后的申请进入审批环节(链路)。每一级上司根据公司政策比如费用上限或是否有票据判断是否继续处理。如果符合条件或该审批者无权审批,申请会被传递到下一个环节。
  3. 财务审核:通过所有审批后,财务部门再进行一次核查,确保链路都是true且符合财务规定。如果审核通过,申请继续流向资金发放环节 (实际的处理方法)。
  4. 资金发放:经过所有环节的条件检查和批准,资金会发放到你的账户中。

每个环节都有自己的条件判断,每个节点只处理自己能处理的部分,不符合条件的节点将被跳过,确保整个流程高效顺畅。

案例

简单点

先来个简单点的,虚拟一个简单的过滤器链实现和实际的使用,用来处理HTTP请求。

抽象处理者

接口定义
1
2
3
4
5
6
7
8
interface Handler : Comparable<Handler> {
var index: Int // 责任链顺序

fun setNext(handler: Handler): Handler // 下一个
fun handleRequest(request: Request) // 处理方法,处理同一种入参

override fun compareTo(other: Handler): Int = this.index - other.index
}

基础处理者

基础实现
1
2
3
4
5
6
7
8
9
10
11
12
13
// 基础处理者,提供处理链传递逻辑,并实现index
abstract class BaseHandler(override var index: Int) : Handler {
private var nextHandler: Handler? = null

override fun setNext(handler: Handler): Handler {
nextHandler = handler
return handler
}

override fun handleRequest(request: Request) {
nextHandler?.handleRequest(request)
}
}

具体处理者

具体实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 具体处理者1:处理认证逻辑
class AuthenticationHandler(index: Int) : BaseHandler(index) {
override fun handleRequest(request: Request) {
if ("ROLE_ADMIN" == request?.role) {
super.handleRequest(request)
} else {
response.WriteError("认证失败")
}
}
}

// 具体处理者2:处理日志记录逻辑
class LoggingHandler(index: Int) : BaseHandler(index) {
override fun handleRequest(request: Request) {
Logger.info("登录:${request.username}")
super.handleRequest(request)
}
}

链管理者

链管理者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 链的管理者:负责组装和管理责任链
class ChainManager {
private val handlers: MutableList<Handler> = mutableListOf()
// 添加处理器到链中,指定顺序
fun addHandler(handler: Handler): ChainManager {
handlers.add(handler)
return this
}
// 从链中移除处理器
fun removeHandler(handler: Handler): ChainManager {
handlers.remove(handler)
return this
}
// 构建责任链
fun buildChain(): Handler? {
if (handlers.isEmpty()) {
throw IllegalArgumentException("空链")
}
// 根据index字段排序
handlers.sort()
// 链接处理器
for (i in 0 until handlers.size - 1) {
handlers[i].setNext(handlers[i + 1])
}
return handlers.firstOrNull()
}
}

链构建者

链构建者
1
2
3
4
5
6
7
8
9
// 链的创建者:工厂类,用于创建责任链
object ChainCreator {
fun createDefaultChain(): Handler? {
val manager = ChainManager()
manager.addHandler(LoggingHandler(2)) // 指定顺序
.addHandler(AuthenticationHandler(1))
return manager.buildChain()
}
}

使用

这里假设将我们虚拟的责任链加入到请求拦截器,真实这里应该是基于HandlerInterceptor实现的处理者。

run
1
2
3
4
5
6
7
8
9
10
11
@Configuration
class WebConfig : WebMvcConfigurer {

override fun addInterceptors(registry: InterceptorRegistry) {
// 创建责任链
val chain = ChainCreator.createDefaultChain()

// 注册责任链的第一个处理者
registry.addInterceptor(chain)
}
}

Spring Web

在 Spring Web 框架中,责任链模式被广泛应用于请求处理的各个阶段,尤其是在处理请求拦截和映射时。

看 Spring Web 案例代码之前,现梳理一遍请求到链路末端处理到返回的逻辑,比如启动并访问 OrderController @GetMapping("/order/list") public ResponseEntity<ResponseRow> list() 方法。

  1. Spring Boot 启动时,SpringApplication.run() 方法会被调用。这一方法负责引导和启动 Spring 应用程序上下文,加载所有的配置类和 Bean。
  2. 理所当然 DispatcherServlet.java 作为核心组件会被通过自动配置机制自动注册并初始化,当作 Spring MVC 的前端控制器,用于接收和处理所有的 HTTP 请求。
  3. DispatcherServlet 初始化时会调用 initHandlerMappings() 方法来加载所有的HandlerMapping 实现类储存到私有属性 private List<HandlerMapping> handlerMappings,并且等待处理即将到来的请求。
  4. HandlerMapping 类负责将请求映射到适当的处理器(例如 @Controller 中的方法)。
  5. 用户发出 /order/list 请求时,DispatcherServlet 作为前端控制器接收 HTTP 请求,在 doDispatch() 方法中遍历 handlerMappings 列表并调用每个 HandlerMapping 实现类的 getHandler() 方法,尝试找到合适的 HandlerExecutionChain 来处理这个请求。
  6. 我们举例是 @GetMapping("/order/list") 所以会用RequestMappingHandlerMapping识别出 OrderController 中相应的处理方法,并返回一个 HandlerExecutionChain。这个 HandlerExecutionChain 包含了处理该请求的控制器方法(如 OrderController.list())以及相关的拦截器链。
  7. 当然拦截器(多个 HandlerInterceptor 以及可能是异步的 AsyncHandlerInterceptorWebRequestHandlerInterceptorAdapter )可能会执行一些通用逻辑,如权限验证、日志记录等,都是按既定顺序执行。如果所有的拦截器都允许请求通过,将调用实际的处理器方法(如 OrderController.list())。
  8. 调用实际的处理器方法后还会继续调用拦截器的 postHandle() 方法,在生成响应之前对结果进一步处理。最后,无论请求是否成功,afterCompletion() 方法都会被调用,此为清理操作。

关系图

DispatcherServlet.java
DispatcherServlet.java
RequestMappingHandlerMapping.java
RequestMappingHandlerMapping.java
抽象处理者、基础处理者、具体处理者
抽象处理者、基础处理者、具体处理者

HandlerInterceptor

抽象处理者 网络请求处理的不同阶段拦截器

public interface HandlerInterceptor {    
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    
        return true;    
    }//调用"Controller"方法之前    
    
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {    
    }//调用"Controller"方法之后渲染"ModelAndView"之前  
      default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {    
    }//渲染"ModelAndView"之后 }  

AsyncHandlerInterceptor

基础处理者 继承了 HandlerInterceptor 接口,并添加了处理异步请求的方法。

public interface AsyncHandlerInterceptor extends HandlerInterceptor {    
    default void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    
}  }  

WebRequestHandlerInterceptorAdapter

具体处理者 实现了 AsyncHandlerInterceptor 接口。并将 WebRequestInterceptor 转换为 HandlerInterceptor。它将 WebRequestInterceptor 的处理逻辑适配为 HTTP 请求处理逻辑,并处理异步请求的逻辑。

public class WebRequestHandlerInterceptorAdapter implements AsyncHandlerInterceptor {    
    private final WebRequestInterceptor requestInterceptor;    
    
    public WebRequestHandlerInterceptorAdapter(WebRequestInterceptor requestInterceptor) {    
        Assert.notNull(requestInterceptor, "WebRequestInterceptor must not be null");    
        this.requestInterceptor = requestInterceptor;    
    }    
    
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    
        this.requestInterceptor.preHandle(new DispatcherServletWebRequest(request, response));    
        return true;    
    }    
    
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {    
        this.requestInterceptor.postHandle(new DispatcherServletWebRequest(request, response), modelAndView != null && !modelAndView.wasCleared() ? modelAndView.getModelMap() : null);    
    }    
    
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {    
        this.requestInterceptor.afterCompletion(new DispatcherServletWebRequest(request, response), ex);    
    }    
    
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) {    
        WebRequestInterceptor var5 = this.requestInterceptor;    
        if (var5 instanceof AsyncWebRequestInterceptor asyncInterceptor) {    
            DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response);    
            asyncInterceptor.afterConcurrentHandlingStarted(webRequest);    
        }    
    
}  }  

DispatcherServlet

客户端 该调度程序负责配置和执行拦截器链。Spring MVC 的前端控制器,用于接收和处理所有的 HTTP 请求。

这条链路客户端到处理器中间其实还有两个部分,稍后就有介绍
HandlerMapping:用于查找与请求匹配的处理器(Controller),并返回HandlerExecutionChain
HandlerExecutionChain:包含处理器和一系列拦截器(处理器)(HandlerInterceptor)。它负责在请求处理过程中依次调用链中的拦截器。

public class DispatcherServlet extends FrameworkServlet {  
    ...    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {        HandlerExecutionChain mappedHandler = null;        ...        // 获取处理链  
        mappedHandler = this.getHandler(processedRequest);        ...    }    ...    @Nullable    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {    
        if (this.handlerMappings != null) {    
            Iterator var2 = this.handlerMappings.iterator();    
        
            while(var2.hasNext()) {    
                HandlerMapping mapping = (HandlerMapping)var2.next();    
                HandlerExecutionChain handler = mapping.getHandler(request);    
                if (handler != null) {    
                    return handler;    
                }    
            }    
        }    
        
        return null;    
    }  
    ...}  
  

HandlerExecutionChain

处理链管理者 Spring Web中需要一个角色,将处理器和拦截器链组织在一起,按照顺序处理请求。

它是一个管理处理器和拦截器链的组件。在处理请求时,它负责管理和调用所有的拦截器方法,并最终调用实际的处理器(例如 Controller)。

HandlerMapping

链的建立者 Spring Web中需要一个角色,负责从请求中确定合适的处理器,并将处理器与拦截器链组合起来,形成一个完整的处理链(也就是HandlerExecutionChain)。

它可以被视为该条责任链的启动点或“链的建立者”。它确定了请求将由哪个处理器处理,并且可能为处理器配置了一些拦截器。

总结

优点

  • 业务解耦:每个节点独立可以随时新增或删除,不仅不会影响事务请求的业务代码,还不会影响其它责任节点。
  • 责任单一:责任链每个节点处理的对象是同一种,但是每个节点处理的事务不一样。
  • 动态组合:节点之间有强秩序,但是可以根据不同业务动态重新组合成一个新链路。

缺点

  • 性能缺陷:节点之间有强秩序,大概率会走完全部链路,必影响耗时。
  • 死循环:链路过长开发人员不熟悉整个流程一样难以新增节点,容易出现链路闭环。即新增的F节点可能下一步需要B, 但是要在C之前,便出现 B->D->C->F->B。当然这个问题在开发阶段能处理。

本站由 钟意 使用 Stellar 1.28.1 主题创建。
又拍云 提供CDN加速/云存储服务
vercel 提供托管服务
湘ICP备2023019799号-1
总访问 次 | 本页访问