观察者模式?

2025年 阅读约 10 分钟 面试指南 · 设计模式

深入解析观察者模式:发布订阅模型、Java内置Observer/Observable、Spring事件机制(ApplicationEvent)、Guava EventBus、MQ异步解耦,附面试模拟问答。

一句话总结

观察者模式定义对象间一对多依赖,当一个对象状态改变时,所有依赖者自动收到通知。核心角色: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 + ObserverPublisher + Broker + Subscriber
典型实现Spring ApplicationEventMQ(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 在事务提交后才执行,保证数据一致性,避免事务未提交监听器就读到脏数据。