开个坑补齐设计模式系列笔记, 顺带回顾Spring源码中的设计模式运用…
模式
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许多个对象有机会处理同一个请求,从而避免请求的发送者与多个接收者之间的耦合, 通常用于请求有多个阶段。该模式通过将这些对象连成一条链,并沿着链传递请求,直到有一个对象处理请求为止。如果链的末端没有对象处理请求,整个请求将被丢弃或默认处理。
未加粗的是责任链复杂程度上去之后可选的角色
- 抽象处理者(Handler):
- 定义:一个接口或抽象类,通常包含一个方法来处理请求以及一个方法来设置下一个处理者。它规定了所有具体处理者都必须实现的基本操作,如处理请求或将请求传递给链中的下一个处理者。
- 角色:接口或抽象类 作为处理链的核心定义,保证每个处理者都具有处理请求的能力。
- 基础处理者 (Base Handler): 可选
- 定义:一个接口或部分实现类,它实现了抽象处理者的部分功能或是抽象处理者的拓展。
- 角色:复用和扩展 提供公共的逻辑实现,减少子类的重复代码,增强代码的可复用性。
- 具体处理者(ConcreteHandlers):
- 定义:每个实现类,实现了处理某种请求的逻辑。当它无法处理请求时,会将请求传递给链中的下一个处理者。
- 角色:链的节点实现 实现自己的处理逻辑来参与责任链的请求处理。
- 链的管理者(Chain Manager):可选
- 定义:通常是一个Chain类,实现创建和管理处理者的顺序、组装责任链,并维护链的整体状态。
- 角色:构建和维护责任链 确保处理者按照正确的顺序处理请求,同时可以动态地添加、移除或调整链中的处理者。
- 链的构造器(Chain Creator):可选
- 定义:通常是一个工厂类或构造器,负责初始化责任链的结构并返回链的起始处理者。它可以根据具体的业务需求,创建不同类型的责任链。
- 角色:生成责任链实例 确保处理者按照正确的顺序处理请求,同时可以动态地添加、移除或调整链中的处理者。
- 客户类(Client):
- 定义:客户类是发起请求的对象,它通常会自行或调用链的构造器创建并设置责任链,然后向责任链的第一个处理者提交请求。
- 角色:责任链的创建者 请求的发起者
场景
公司报销流程就像一条责任链,每个环节都根据条件决定是否继续处理:
- 填写申请:你提交的报销单是链上的第一个环节,检查所有必要的字段和金额,确保格式正确。如果不符合条件,它会被退回。
- 审批环节:提交后的申请进入审批环节(链路)。每一级上司根据公司政策比如费用上限或是否有票据判断是否继续处理。如果符合条件或该审批者无权审批,申请会被传递到下一个环节。
- 财务审核:通过所有审批后,财务部门再进行一次核查,确保链路都是
true
且符合财务规定。如果审核通过,申请继续流向资金发放环节 (实际的处理方法)。 - 资金发放:经过所有环节的条件检查和批准,资金会发放到你的账户中。
每个环节都有自己的条件判断,每个节点只处理自己能处理的部分,不符合条件的节点将被跳过,确保整个流程高效顺畅。
案例
简单点
先来个简单点的,虚拟一个简单的过滤器链实现和实际的使用,用来处理HTTP请求。
抽象处理者
1 |
|
基础处理者
1 |
|
具体处理者
1 |
|
链管理者
1 |
|
链构建者
1 |
|
使用
这里假设将我们虚拟的责任链加入到请求拦截器,真实这里应该是基于
HandlerInterceptor
实现的处理者。
1 |
|
Spring Web
在 Spring Web 框架中,责任链模式被广泛应用于请求处理的各个阶段,尤其是在处理请求拦截和映射时。
看 Spring Web 案例代码之前,现梳理一遍请求到链路末端处理到返回的逻辑,比如启动并访问 OrderController
的 @GetMapping("/order/list")
的 public ResponseEntity<ResponseRow> list()
方法。
- Spring Boot 启动时,
SpringApplication.run()
方法会被调用。这一方法负责引导和启动 Spring 应用程序上下文,加载所有的配置类和 Bean。 - 理所当然 DispatcherServlet.java 作为核心组件会被通过自动配置机制自动注册并初始化,当作 Spring MVC 的前端控制器,用于接收和处理所有的 HTTP 请求。
DispatcherServlet
初始化时会调用 initHandlerMappings() 方法来加载所有的HandlerMapping
实现类储存到私有属性private List<HandlerMapping> handlerMappings
,并且等待处理即将到来的请求。- HandlerMapping 类负责将请求映射到适当的处理器(例如
@Controller
中的方法)。 - 用户发出
/order/list
请求时,DispatcherServlet
作为前端控制器接收 HTTP 请求,在 doDispatch() 方法中遍历handlerMappings
列表并调用每个HandlerMapping
实现类的getHandler()
方法,尝试找到合适的HandlerExecutionChain
来处理这个请求。 - 我们举例是
@GetMapping("/order/list")
所以会用RequestMappingHandlerMapping识别出OrderController
中相应的处理方法,并返回一个HandlerExecutionChain
。这个HandlerExecutionChain
包含了处理该请求的控制器方法(如OrderController.list()
)以及相关的拦截器链。 - 当然拦截器(多个
HandlerInterceptor
以及可能是异步的AsyncHandlerInterceptor
和WebRequestHandlerInterceptorAdapter
)可能会执行一些通用逻辑,如权限验证、日志记录等,都是按既定顺序执行。如果所有的拦截器都允许请求通过,将调用实际的处理器方法(如OrderController.list()
)。 - 调用实际的处理器方法后还会继续调用拦截器的
postHandle()
方法,在生成响应之前对结果进一步处理。最后,无论请求是否成功,afterCompletion()
方法都会被调用,此为清理操作。
关系图
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。当然这个问题在开发阶段能处理。