阅读视图

发现新文章,点击刷新页面。
🔲 ☆

设计模式系列——观察者模式

模式

一种订阅机制, 在可观察对象事件发生时通知多个 “观察” 该对象的其他对象。中文以订阅者(观察者)和订阅对象(可观察对象)更容易理解,而发布者理解为统一的通知部门。

啊〰老师老师,有人就要问了,为什么不用Kafka?Redis?RabbitMQ?
没有为什么,Kafka、Redis、RabbitMQ都是消息队列,但观察者模式是一种更加通用的模式,可以用于非使命必达的场景。

  1. 发布者 (Publisher):
    • 定义:当可观察对象发生变更,筛选对应的订阅者并发布他们关注的内容
  2. 订阅者 (Subscriber):
    • 定义:除了有update方法,订阅者还需要实现逻辑来处理发布者的通知参数

场景

这个模式的生活场景巨多,就比如 一蓑烟雨 的博客就有文章订阅 哈哈哈

  • 邮箱订阅:给感兴趣的人推送更新,当然现在不感兴趣也会被迫收到。
  • 期刊订阅:小学订阅的小学生之友,还有英语老师让大家(可自愿)订阅的英语报。
  • 菜市场:和老板娘说有漂亮的五花肉记得打电话给我。就是她有时候会忘记。
  • 群聊通知:排除掉开启了免打扰的成员,剩下的都是订阅者。

案例

简单点

一个商品降价订阅通知,商品为小米SU7,为了能在线分享用 TypeScript 写案例分享。

以下代码点击 codesandbox 按钮即可运行。
Edit ThatCoder-Design

观察者接口

定义了基本的观察者接口,有观察者的信息和可观察对象的变更回调方法update()

观察者接口
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
28
29
30
31
// Observer.ts 观察者接口
export interface Observer {
  // 可观察对象变更回调
  update(product: string, price: number): void;
  userUUID: string;
  email: string;
  subscriptionType: SubscriptionType;
  discountThreshold?: number; // 仅对 DISCOUNT_TO 类型有效
}

// 订阅类型枚举
export class SubscriptionType {
  private constructor(public readonly model: string) {}

  static readonly IN_STOCK = new SubscriptionType("IN_STOCK");
  static readonly DISCOUNT = new SubscriptionType("DISCOUNT");
  static readonly DISCOUNT_TO = new SubscriptionType("DISCOUNT_TO");

  getDescription(): string {
    switch (this.model) {
      case "IN_STOCK":
        return "来货通知";
      case "DISCOUNT":
        return "降价通知";
      case "DISCOUNT_TO":
        return "降价到预期通知";
      default:
        return "未知订阅";
    }
  }
}

观察者实现

实现了观察者,增加了发送邮箱这个实际的通知方法,在update()实现通知调用

观察者接口
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
28
29
30
31
32
33
34
// UserObserver.ts 实现具体的观察者,处理不同类型的通知
import {logger} from "../util/Logger"
import { Observer, SubscriptionType } from "./Observer";

export class UserObserver implements Observer {
  constructor(
    public userUUID: string,
    public email: string,
    public subscriptionType: SubscriptionType,
    public discountThreshold?: number // 仅对 DISCOUNT_TO 类型有效
  ) {}

  update(product: string, price: number): void {
    switch (this.subscriptionType) {
      case SubscriptionType.IN_STOCK:
        this.sendEmailNotification(`${product} 来货了!`);
        break;
      case SubscriptionType.DISCOUNT:
        this.sendEmailNotification(`${product} 现在已经降价至 $${price}!`);
        break;
      case SubscriptionType.DISCOUNT_TO:
        this.sendEmailNotification(
          `${product} 现在已经降价至 $${price}, 满足您期待的降价 $${
            this.discountThreshold ?? 0
          }% !`
        );
        break;
    }
  }

  private sendEmailNotification(message: string): void {
    logger.info(`发送邮件 ${this.email}: ${message}`);
  }
}

可观察者接口

定义了基本的可观察者接口,主要有订阅、取消订阅、通知三要素。

可观察者接口
1
2
3
4
5
6
7
8
9
10
11
12
13
// Observable.ts 定义一个可观察对象接口,包括订阅、取消订阅和通知方法
import { Observer } from "../Observer";

export interface Observable {
  // 订阅
  subscribe(observer: Observer): void;

  // 取消订阅
  unsubscribe(observer: Observer): void;

  // 通知
  notifyObservers(): void;
}

可观察者实现

实现了一个商品观察对象

可观察者实现
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// ProductObservable.ts  实现具体的可观察对象(商品通知器)
import { Observable } from "./Observable";
import { Observer, SubscriptionType } from "../Observer";
import { logger } from "../../util/Logger";

export class ProductObservable implements Observable {
  private publishers: Observer[] = [];
  private currentPrice: number = 0.0;
  private originalPrice: number = 100.0; // 原始价格,用于比较

  constructor(private product: string) {
    logger.info(
      `创建可观察对象(商品:${product}),价格 $${this.originalPrice}`
    );
  }

  subscribe(publisher: Observer): void {
    this.publishers.push(publisher);
    logger.info(
      `用户UUID: ${publisher.userUUID} ,成功订阅商品 ${
        this.product
      } ,订阅类型 ${publisher.subscriptionType.getDescription()}.`
    );
  }

  unsubscribe(publisher: Observer): void {
    this.publishers = this.publishers.filter(
      (obs) => obs.userUUID !== publisher.userUUID
    );
    logger.info(
      `用户UUID: ${publisher.userUUID} ,取消订阅商品 ${this.product} `
    );
  }

  notifyObservers(): void {
    for (const publisher of this.publishers) {
      switch (publisher.subscriptionType) {
        case SubscriptionType.IN_STOCK:
          publisher.update(this.product, this.currentPrice);
          break;
        case SubscriptionType.DISCOUNT:
          if (this.currentPrice < this.originalPrice) {
            publisher.update(this.product, this.currentPrice);
          }
          break;
        case SubscriptionType.DISCOUNT_TO:
          if (this.currentPrice <= (publisher.discountThreshold ?? 0)) {
            publisher.update(this.product, this.currentPrice);
          }
          break;
      }
    }
  }

  productRestocked(): void {
    logger.info(`商品 ${this.product} 采购成功`);
    this.notifyObservers();
  }

  productDiscounted(newPrice: number): void {
    this.currentPrice = newPrice;
    if (newPrice === this.originalPrice) {
      logger.info(`商品 ${this.product} 恢复原价`);
    } else {
      logger.info(`商品 ${this.product} 降价至: $${this.currentPrice}`);
    }
    this.notifyObservers();
  }
}

测试效果

创建 小米SU7 这个可观察对象
三个用户关注了 小米SU7,关注类型不一样
在 小米SU7 库存和价格变动时候可以观测到对应的通知变化

测试
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// main.ts
import { ProductObservable } from "./observable/ProductObservable";
import { UserObserver } from "./UserObserver";
import { SubscriptionType } from "./Observer";
import { logger } from "../util/Logger";

export const TestObserver = () => {
  // 创建可观察对象(商品通知器)
  const su7Notifier = new ProductObservable("小米SU7");

  // 创建观察者(用户)
  const user1 = new UserObserver(
    "UUID-1111",
    "user1@thatcoder.cn",
    SubscriptionType.IN_STOCK
  );
  const user2 = new UserObserver(
    "UUID-2222",
    "user2@thatcoder.cn",
    SubscriptionType.DISCOUNT
  );
  const user3 = new UserObserver(
    "UUID-3333",
    "user3@thatcoder.cn",
    SubscriptionType.DISCOUNT_TO,
    50
  );

  // 用户1订阅iPhone 15有货通知
  su7Notifier.subscribe(user1);
  // 用户2订阅iPhone 15降价通知
  su7Notifier.subscribe(user2);
  // 用户3订阅iPhone 15降价到50%通知
  su7Notifier.subscribe(user3);

  // 商品到货,通知相关用户
  su7Notifier.productRestocked();

  // 商品降价,通知相关用户
  su7Notifier.productDiscounted(60.0);

  // 商品恢复原价
  su7Notifier.productDiscounted(100.0);

  // 商品降价到50%,通知相关用户
  su7Notifier.productDiscounted(45.0);

  // 用户1取消iPhone 15的订阅
  su7Notifier.unsubscribe(user1);

  // 商品到货,通知剩余的用户
  su7Notifier.productRestocked();
};

测试结果

和预想一致,可观察对象只需要关注自己的变动就可以了,用户考虑的就多了(还要点击订阅)。
降价到60,所以用户3不被通知
用户1取消订阅,所以来货了也不被通知
当然这是最简单的示例

运行结果
运行结果

Spring监听机制

Spring有EventListener类似去定义一个事件的处理逻辑,相当于在里面写了订阅者的通知方法。ApplicationEventPublisher会去发布定义的事件,相当于可观察者的对象发生了变动。不同的是我们只关心发布和处理逻辑即可,中间的调用交给了Listener

生命周期事件

在包 org.springframework.context.event 下面有很多与 ApplicationContext 生命周期相关的事件,这些事件都继承自 ApplicationContextEvent,包括 ContextRefreshedEvent, ContextStartedEvent, ContextStoppedEvent, ContextClosedEvent
到了对应的生命周期会调用订阅。

启动和刷新
1
2
3
4
5
6
7
8
9
10
import org.springframework.context.ApplicationListener
import org.springframework.context.event.ContextRefreshedEvent
import org.springframework.stereotype.Component

@Component
class StartupListener : ApplicationListener<ContextRefreshedEvent> {
override fun onApplicationEvent(event: ContextRefreshedEvent) {
println("应用刷新成功!")
}
}

事务监听

@TransactionalEventListener
举例一个下单成功后的发布事务

事件定义
1
data class OrderPlacedEvent(val orderId: String, val userEmail: String)
事件处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import org.springframework.context.event.TransactionalEventListener
import org.springframework.stereotype.Component

@Component
class OrderPlacedEventListener {

@TransactionalEventListener
@Async
fun handleOrderPlacedEvent(event: OrderPlacedEvent) {
// 发送订单确认邮件
val orderId = event.orderId
val userEmail = event.userEmail
println("发送 $orderId 信息到用户邮箱 $userEmail")
// 实际发送邮件的逻辑...
}
}
事件触发
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class OrderService(private val eventPublisher: ApplicationEventPublisher) {

@Transactional
fun save(order: Order) {
// 处理下单逻辑...
// 发布事件
eventPublisher.publishEvent(OrderPlacedEvent(orderId, userEmail))
}
}

总结

优点

  • 代码解耦:观察者和订阅者的逻辑分开,订阅者只引用了抽象的发布者接口,每个可观察者只需要关注自己的实现。
  • 抽象耦合:如上代码解耦后逻辑上依然保持着抽象的耦合,订阅者只需要注册订阅即可

缺点

  • 隐式依赖:抽象耦合就代表着事件通知机制是隐式的,系统的行为可能变得难以预测和理解。及时补充文档,不然就慢慢DEBUG。
  • 瞬时峰值:某个可观察对象有大量订阅时,触发update带来的巨额性能开销可能会导致性能瓶颈,甚至系统阻塞。注意异步和削峰。
  • 并发问题:多线程中,事件的发布和订阅者的变动可能带来并发问题。需要复杂的同步机制来确保线程安全,比如ConcurrentModificationException。除了线程安全的集合可能还需要考虑显式锁、读写锁或原子操作。
IDEA的监听耳机
IDEA的监听耳机
🔲 ☆

设计模式系列——责任链模式

开个坑补齐设计模式系列笔记, 顺带回顾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。当然这个问题在开发阶段能处理。
❌