观察者模式(Observer Pattern)是一种经典的行为型设计模式 ,它解决的是对象间一对多依赖关系的问题:当一个对象(被观察者 / Subject)的状态发生变化时,自动通知依赖它的多个对象(观察者 / Observer)做出响应。
一、核心思想
让数据的变化与响应的行为解耦 。
在没有这个模式前,你可能写出这样的代码:
user.setName("Alice");
logger.log("User name changed");
emailService.notifyAdmin("User name changed");
这让 User 对象不得不关心谁在监听它。逻辑交织、耦合紧密。
使用观察者模式后,User 不再主动调用任何服务,而是提供一种注册机制:
user.addObserver(logger);
user.addObserver(emailService);
当 user.setName("Alice") 触发变化时,所有注册的观察者都会自动收到通知。
二、结构角色
观察者模式主要有四类角色:
| 角色 | 说明 |
|---|---|
| Subject(抽象被观察者) | 定义注册、移除、通知观察者的接口 |
| ConcreteSubject(具体被观察者) | 保存具体状态,状态变化时调用通知方法 |
| Observer(抽象观察者) | 定义接收更新的方法(如 update()) |
| ConcreteObserver(具体观察者) | 实现更新接口,根据被观察者状态做出响应 |
结构图:

- 说明:把观察者和被观察者解耦,被观察者不直接依赖观察者,只通过通知接口告知状态变化。
三、简单示例
// 观察者接口
interface Observer {
void update(String message);
}
// 被观察者抽象类
class Subject {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer o) { observers.add(o); }
public void removeObserver(Observer o) { observers.remove(o); }
protected void notifyObservers(String message) {
for (Observer o : observers) {
o.update(message);
}
}
}
// 具体被观察者
class WeatherStation extends Subject {
private String weather;
public void setWeather(String weather) {
this.weather = weather;
notifyObservers("天气更新为: " + weather);
}
}
// 具体观察者
class AppDisplay implements Observer {
public void update(String message) { System.out.println("App显示:" + message); }
}
class EmailAlert implements Observer {
public void update(String message) { System.out.println("邮件提醒:" + message); }
}
// 测试
public class Demo {
public static void main(String[] args) {
WeatherStation ws = new WeatherStation();
ws.addObserver(new AppDisplay());
ws.addObserver(new EmailAlert());
ws.setWeather("多云转晴");
}
}
四、Spring 中的观察者模式
Spring 的事件(Spring Event )机制,是 Spring 容器中对观察者模式 的一个完善实现。它提供了 发布-订阅模型(Publish-Subscribe) 的标准化支持,用于在应用内部解耦组件,让 Bean 之间通过事件进行通信。
1. Spring Event 设计思想
Spring Event 实现了观察者模式的核心结构:
| 角色 | 对应 |
|---|---|
| Subject(被观察者) | ApplicationContext(事件源) |
| Observer(观察者) | ApplicationListener |
| Event(事件) | ApplicationEvent |
| 通知机制 | ApplicationEventMulticaster |
所以可以理解为:
ApplicationContext负责发布事件,ApplicationListener负责监听事件,ApplicationEventMulticaster负责广播事件。
2、核心类结构
a. ApplicationEvent
-
所有事件的基类(从 Spring 4.2 开始,也可以直接使用任意对象作为事件)。
-
包含事件源信息(
source)与时间戳。
示例:
public class UserRegisterEvent extends ApplicationEvent {
private final String username;
public UserRegisterEvent(Object source, String username) {
super(source);
this.username = username;
}
public String getUsername() {
return username;
}
}
b. ApplicationListener
-
事件监听器接口,接收并处理事件。
-
泛型指定感兴趣的事件类型。
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisterEvent> {
@Override
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println("发送欢迎邮件给用户:" + event.getUsername());
}
}
c. ApplicationEventPublisher
-
事件发布接口,
ApplicationContext实现了它。 -
任何 Bean 都可以通过注入该接口来发布事件。
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher publisher;public void registerUser(String username) { // 注册逻辑... publisher.publishEvent(new UserRegisterEvent(this, username)); }}
d. ApplicationEventMulticaster
-
事件广播器,负责查找匹配的监听器并调用。
-
默认实现类为
SimpleApplicationEventMulticaster。 -
支持同步和异步事件分发。
@Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); // 异步事件
return multicaster;
}
3、事件调用流程(核心机制)
Spring Event 的内部调用链如下:
-
事件发布
- 通过
ApplicationEventPublisher.publishEvent()发布事件。
- 通过
-
事件广播
ApplicationEventMulticaster收到事件 → 查找所有匹配的监听器。
-
事件分发
-
调用每个
ApplicationListener.onApplicationEvent()。 -
默认同步执行,可配置为异步。
-
-
监听器响应
- 监听器执行对应业务逻辑。
可用简图表示:
UserService
↓
publishEvent(UserRegisterEvent)
↓
ApplicationContext(ApplicationEventPublisher)
↓
ApplicationEventMulticaster
↓
┌─────────────────────┬────────────────────┐
│ WelcomeEmailListener│ LogRecordListener │
└─────────────────────┴────────────────────┘
4、异步事件处理
默认情况下,Spring 事件是同步执行的。
若要实现异步(防止阻塞主线程),有两种方式:
方式一:在 ApplicationEventMulticaster 中配置线程池
@Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
public SimpleApplicationEventMulticaster asyncEventMulticaster() {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setTaskExecutor(Executors.newFixedThreadPool(5));
return multicaster;
}
方式二:使用 @Async
@Component
public class AsyncEmailListener {
@Async
@EventListener
public void handle(UserRegisterEvent event) {
System.out.println("异步发送邮件给:" + event.getUsername());
}
}
5、基于注解的事件监听(推荐)
Spring 4.2 之后,可以用 @EventListener 代替实现接口:
@Component
public class AnnotatedListener {
@EventListener
public void handleUserRegister(UserRegisterEvent event) {
System.out.println("记录日志:新用户注册 -> " + event.getUsername());
}
}
甚至支持条件过滤:
@EventListener(condition = "#event.username.startsWith('admin')")
public void handleAdminRegister(UserRegisterEvent event) {
System.out.println("管理员注册:" + event.getUsername());
}
6、应用场景
Spring Event 非常适合用于业务解耦场景:
| 场景 | 示例 |
|---|---|
| 用户注册 | 触发欢迎邮件、积分初始化、日志记录 |
| 订单支付 | 通知库存系统、积分系统、消息推送 |
| 系统监控 | 异常上报、埋点、指标采集 |
| 模块通信 | 不同模块之间基于事件进行低耦合通信 |
在微服务架构中,这个机制在单体内部就像一个"轻量版的消息队列"。
五、与其它设计模式对比
1. 观察者模式 vs. 责任链模式(Chain of Responsibility)
| 对比项 | 观察者模式 | 责任链模式 |
|---|---|---|
| 通知方式 | 一对多并行通知 | 一对一链式传递 |
| 执行顺序 | 同时通知多个观察者 | 顺序传递直到被处理 |
| 目的 | 广播事件 | 分级处理请求 |
| 示例 | Spring Event 广播 | Servlet Filter / Spring Security FilterChain |
区别本质:
-
观察者是"群发通知";
-
责任链是"层层转交"。
2. 观察者模式 vs. 中介者模式(Mediator Pattern)
| 对比项 | 观察者模式 | 中介者模式 |
|---|---|---|
| 结构 | 被观察者与观察者间通信 | 所有对象通过中介通信 |
| 关系 | 一对多 | 多对多(通过中心协调) |
| 关注点 | 状态变化通知 | 复杂对象交互管理 |
| 示例 | GUI 事件模型 | 聊天室服务器、航班调度系统 |
中介者是一个"事件中心 ",
而观察者模式是一个"事件传播机制"。
3. 观察者模式 vs. 命令模式(Command Pattern)
| 对比项 | 观察者模式 | 命令模式 |
|---|---|---|
| 意图 | 状态变更触发通知 | 封装请求为对象 |
| 调用关系 | 被动(事件驱动) | 主动(命令调用) |
| 适用场景 | 状态同步、事件响应 | 动作封装、可撤销操作 |
| 示例 | Spring Event 监听 | Spring Task、命令执行器 |
可以协作使用 :
比如一个观察者响应事件后执行具体命令(Command)。
4. 观察者模式 vs. 装饰器模式(Decorator Pattern)
| 对比项 | 观察者模式 | 装饰器模式 |
|---|---|---|
| 目的 | 对象间通信 | 动态扩展功能 |
| 结构 | 事件驱动 | 包装增强 |
| 时机 | 运行时响应 | 运行时功能组合 |
| 示例 | 监听注册事件 | I/O 流的层层包装 |
观察者像"通知别人我变了",
而装饰器是"我穿上外衣变强了"。
六、拓展
-
响应式流(Reactive Stream) :
Observer演化为Subscriber,Subject变为Publisher。它们支持背压(Backpressure),防止"观察者被淹没"。 -
单播 vs. 多播 :单播(Reactor 中的
Mono)是一对一的观察关系;多播(Flux)是一对多。 -
观察者是"事件驱动架构(EDA)"的基石。它让系统从 命令式逻辑(do A then B)转向响应式逻辑(when A happens, notify B)。
在复杂系统中,它常常与下列模式配合:
-
与 工厂模式 配合,用于动态注册观察者;
-
与 策略模式 配合,用于灵活决定响应策略;
-
与 单例模式 配合,用于全局事件中心;
-
与 命令模式 配合,用于事件触发具体动作。