25小节:使用观察者模式重构配置动态刷新
作者:程序员马丁
热门项目实战社群,收获国内众多知名公司面试青睐,近千名同学面试成功!助力你在校招或社招上拿个offer。
使用观察者模式重构配置动态刷新,元数据信息:
- 什么是线程池oneThread:https://t.zsxq.com/5GfrN
- 代码仓库:https://gitcode.net/nageoffer/onethread —— 申请项目权限参考上述线程池项目链接
- 章节难度:★★★☆☆ - 较难
- 视频地址:文档先行视频次之
©版权所有 - 拿个offer-开源&项目实战星球专属学习项目,依据《中华人民共和国著作权法实施条例》和《知识星球产权保护》,严禁未经本项目原作者明确书面授权擅自分享至 GitHub、Gitee 等任何开放平台。违者将面临法律追究。
内容摘要:本文深入剖析了 oneThread 动态线程池框架中跨模块通信的设计挑战,通过对配置中心 Starter 与 Web Starter 解耦需求的分析,引出观察者模式在框架架构中的核心价值。文章从实际业务场景出发,详细解析了观察者模式的设计理念、实现机制以及在动态线程池配置刷新中的具体应用。
课程目录如下所示:
- 前言
- 跨模块通信的设计挑战
- 为什么选择观察者模式?
- 什么是观察者模式?
- oneThread 中的观察者模式实现
- 扩展性分析
- Guava vs Spring 观察者模式
- 文末总结
前言
在构建 oneThread 动态线程池框架的过程中,我们面临着一个经典的架构设计问题:如何在保持模块独立性的前提下,实现跨模块的高效通信?
特别是在配置中心 Starter 需要通知 Web Starter 进行线程池参数更新时,传统的直接依赖方式会带来模块耦合、包体积膨胀等问题。为了解决这一挑战,我们引入了观察者模式,构建了一套松耦合、高扩展的事件驱动架构。
本文将带你深入了解这一设计决策的来龙去脉,以及观察者模式在 oneThread 框架中的精妙应用。
跨模块通信的设计挑战
1. 模块架构概览
oneThread 框架采用分层模块化设计,主要包含以下核心模块:
.
└── starter # 动态线程池配置中心组件包,实现线程池结合Spring框架和配置中心动态刷新
├── adapter # 动态线程池适配层,比如对接 Web 容器 Tomcat 线程池等
│ └── web-spring-boot-starter # Web 容器线程池组件库
├── apollo-spring-boot-starter # Apollo 配置中心动态监控线程池组件库
├── common-spring-boot-starter # 配置中心公共监听等逻辑抽象组件库
├── dashboard-dev-spring-boot-starter # 控制台 API 组件库
└── nacos-cloud-spring-boot-starter # Nacos 配置中心动态监控线程池组件库
和本 文章相关的在 starter 模块下,子模块职责如下:
- common-spring-boot-starter:提供配置解析、事件定义等公共能力。
- nacos/apollo-spring-boot-starter:监听配置中心变更,触发刷新逻辑。
- web-spring-boot-starter:管理 Web 容器线程池,响应配置变更。
如果采用直接依赖的方式解决跨模块通信,会面临以下问题:
- 配置中心相关的 Starter 依赖 web-starter,如果用户仅需要动态线程池依赖,无法按需依赖。
- 扩展性差,每增加一种线程池适配器(如 Dubbo、Hystrix 等),都需要修改配置中心 Starter 代码,增加新的依赖关系等。
代码耦合如下所示:
// 配置中心 Starter 需要了解所有可能的线程池类型
public class AbstractDynamicThreadPoolRefresher {
@Autowired(required = false)
private WebThreadPoolService webService;
@Autowired(required = false)
private RocketMQThreadPoolService rocketMQService;
@Autowired(required = false)
private RabbitMQThreadPoolService rabbitMQService;
public void refreshConfig(String config) {
if (webService != null) {
webService.update(config);
}
if (rocketMQService != null) {
rocketMQService.update(config);
}
// ... 更多if判断
}
}
2. 理想的解决方案
我们需要一种机制,能够完成以下需求:
- 解耦模块依赖:配置中心 Starter 无需直接依赖具体的线程池管理模块。
- 支持动态扩展:新增线程池适配器时,无需修改现有代码。
- 保持高内聚:每个模块专注自己的核心职责 。
- 简化测试:模块间松耦合,便于单元测试和集成测试。
为什么选择观察者模式?
1. 业务场景分析
在 oneThread 框架中,配置变更的处理流程如下:
配置中心变更 → 配置解析 → 参数对比 → 线程池更新 → 变更通知
这个流程中存在典型的"一对多"通知场景:
- 一个事件源:配置中心的配置变更。
- 多个观察者:动态线程池 管理器、Web 线程池管理器、RocketMQ 线程池管理器、自定义线程池管理器等。甚至加点想象力,是不是连接池动态变更也能做。
2. 观察者模式的优势
2.1 松耦合设计
2.2 动态扩展能力
新增线程池适配器时,只需:
- 开发监听者,实现
ApplicationListener<ThreadPoolConfigUpdateEvent>
接口。 - 将监听者注册为 Spring Bean,无需修改任何现有代码。
这种方案设计下,职责分离足够清晰:
- 配置中心模块:专注配置监听和解析。
- 线程池管理模块:不同组件专注自己职责内的线程池参数更新。
- 事件机制:负责消息传递和路由。
什么是观察者模式?
1. 观察者模式定义
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
2. 核心角色
- Subject(主题/被观察者):维护观察者列表,提供注册、移除观察者的方法。
- Observer(观察者):定义更新接口,当收到主题通知时执行相应操作。
- ConcreteSubject(具体主题):实现主题接口,状态改变时通知所有观察者。
- ConcreteObserver(具体观察者):实现观察者接口,定义具体的更新逻辑。
3. 经典实现示例
以新闻订阅为例,展示观察者模式的基本实现:
// 观察者接口
public interface NewsObserver {
void update(String news);
}
// 主题接口
public interface NewsSubject {
void addObserver(NewsObserver observer);
void removeObserver(NewsObserver observer);
void notifyObservers(String news);
}
// 具体主题:新闻发布者
public class NewsPublisher implements NewsSubject {
private List<NewsObserver> observers = new ArrayList<>();
@Override
public void addObserver(NewsObserver observer) {
observers.add(observer);
}
@Override
public void removeObserver(NewsObserver observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String news) {
for (NewsObserver observer : observers) {
observer.update(news);
}
}
public void publishNews(String news) {
System.out.println("发布新闻: " + news);
notifyObservers(news);
}
}
// 具体观察者:邮件订阅者
public class EmailSubscriber implements NewsObserver {
private String email;
public EmailSubscriber(String email) {
this.email = email;
}
@Override
public void update(String news) {
System.out.println("邮件通知 " + email + ": " + news);
}
}
// 具体观察者:短信订阅者
public class SMSSubscriber implements NewsObserver {
private String phone;
public SMSSubscriber(String phone) {
this.phone = phone;
}
@Override
public void update(String news) {
System.out.println("短信通知 " + phone + ": " + news);
}
}
观察者模式时序图如下所示:
oneThread 中的观察者模式实现
1. Spring 事件机制
oneThread 框架基于 Spring 的事件发布机制实现观察者模式,这种方式具有以下优势:
- 框架集成:与 Spring 容器深度集成,无需手动管理观察者列表。
- 异步支持:支持同步和异步事件处理。
- 类型安全:基于泛型的强类型事件定义。