一句话总结
观察者模式定义对象间一对多依赖,当一个对象状态改变时,所有依赖者自动收到通知。核心角色:Subject(主题/被观察者)和 Observer(观察者)。Java 内置 Observer/Observable(已废弃),Spring 提供 ApplicationEvent + @EventListener(推荐),Guava EventBus,大规模场景用 MQ 异步解耦。与发布订阅模式的区别:观察者模式中 Subject 和 Observer 直接交互,发布订阅模式通过 Broker 解耦。
初级理解
手写观察者模式
# 观察者接口
public interface Observer {
void update(String message);
}
# 具体观察者
public class UserObserver implements Observer {
private String name;
public UserObserver(String name) { this.name = name; }
public void update(String message) {
System.out.println(name + " 收到消息: " + message);
}
}
# 主题(被观察者)
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notify(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
# 使用
Subject subject = new Subject();
subject.attach(new UserObserver("张三"));
subject.attach(new UserObserver("李四"));
subject.notify("新消息来了!");
# 输出:
# 张三 收到消息: 新消息来了!
# 李四 收到消息: 新消息来了!
中级深入
Spring 事件机制
# 1. 定义事件
public class OrderEvent extends ApplicationEvent {
private Long orderId;
public OrderEvent(Object source, Long orderId) {
super(source);
this.orderId = orderId;
}
public Long getOrderId() { return orderId; }
}
# 2. 发布事件
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;
public void createOrder(Order order) {
// 保存订单...
// 发布事件
publisher.publishEvent(new OrderEvent(this, order.getId()));
}
}
# 3. 监听事件(方式一:@EventListener)
@Component
public class OrderListener {
@EventListener
public void handleOrderEvent(OrderEvent event) {
System.out.println("订单创建: " + event.getOrderId());
// 发送短信、记录日志等
}
}
# 4. 监听事件(方式二:实现 ApplicationListener)
@Component
public class OrderListener2 implements
ApplicationListener<OrderEvent> {
@Override
public void onApplicationEvent(OrderEvent event) {
System.out.println("订单创建2: " + event.getOrderId());
}
}
# 5. 异步事件(需开启 @EnableAsync)
@EventListener
@Async // 异步执行,不阻塞主流程
public void handleOrderEventAsync(OrderEvent event) {
// 耗时操作:发送邮件、同步ES等
}
# 6. 事务事件(事务提交后执行)
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(OrderEvent event) {
// 事务提交后才执行,保证数据一致性
}
高级进阶
观察者 vs 发布订阅
| 对比维度 | 观察者模式 | 发布订阅模式 |
| 耦合度 | Subject 和 Observer 直接交互 | 通过 Broker/EventBus 解耦 |
| 通信方式 | 同步调用 | 异步消息 |
| 组件 | Subject + Observer | Publisher + Broker + Subscriber |
| 典型实现 | Spring ApplicationEvent | MQ(Kafka/RabbitMQ) |
Spring 事件源码分析
# ApplicationEventPublisher.publishEvent() 核心流程:
# 1. ApplicationEventMulticaster.multicastEvent()
# 2. 获取所有匹配的 ApplicationListener
# 3. 如果有线程池(@Async),异步执行
# 4. 否则同步遍历调用 listener.onApplicationEvent()
# 默认实现:SimpleApplicationEventMulticaster
public void multicastEvent(ApplicationEvent event) {
for (ApplicationListener<?> listener :
getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> listener.onApplicationEvent(event));
} else {
listener.onApplicationEvent(event); // 同步
}
}
}
# 注意:
# 1. 默认同步执行,一个监听器异常会影响后续监听器
# 2. 配置线程池后异步执行,异常隔离
# 3. @TransactionalEventListener 在事务提交后才执行
实战场景
# 场景1:用户注册后发送欢迎邮件+初始化账户
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher publisher;
@Transactional
public void register(User user) {
userMapper.insert(user);
publisher.publishEvent(new UserRegisterEvent(this, user));
}
}
@Component
public class UserRegisterListener {
@EventListener
@Async
public void sendWelcomeEmail(UserRegisterEvent event) {
emailService.send(event.getUser().getEmail(), "欢迎注册");
}
@EventListener
@Async
public void initAccount(UserRegisterEvent event) {
accountService.init(event.getUser().getId());
}
}
# 场景2:订单状态变更通知
# 订单支付成功 → 发短信 + 减库存 + 记录日志
# 用事件机制解耦,各监听器独立处理
# 场景3:配置变更通知(Nacos/Apollo)
# 配置中心变更 → 发布 RefreshEvent
# → @RefreshScope 的 Bean 重新初始化
面试模拟
面试官:观察者模式和发布订阅模式有什么区别?
你:观察者模式中 Subject 和 Observer 直接交互,耦合度高,通常是同步调用。发布订阅模式通过 Broker(消息中间件/EventBus)解耦,Publisher 和 Subscriber 互不知道对方存在,通常是异步通信。Spring ApplicationEvent 是观察者模式,MQ 是发布订阅模式。
面试官:Spring 事件机制的原理?@TransactionalEventListener 有什么用?
你:通过 ApplicationEventPublisher 发布事件,ApplicationEventMulticaster 广播给所有匹配的 ApplicationListener。默认同步执行,@Async 可异步。@TransactionalEventListener 在事务提交后才执行,保证数据一致性,避免事务未提交监听器就读到脏数据。