观察者模式
问题
什么是观察者模式?和发布-订阅模式有什么区别?Spring 中如何使用事件机制?
答案
核心思想
定义对象间的一对多依赖关系:当一个对象(Subject)状态改变时,所有依赖它的对象(Observer)自动收到通知并更新。
观察者 vs 发布订阅
| 维度 | 观察者模式 | 发布订阅模式 |
|---|---|---|
| 耦合度 | Subject 直接持有 Observer 引用 | 通过事件中心/消息中间件解耦 |
| 通信方式 | 同步调用 | 可以异步 |
| 典型实现 | JDK Observer、Guava EventBus | Spring Event、MQ |
手写观察者模式
简单观察者实现
// 观察者接口
public interface OrderEventListener {
void onOrderCreated(Order order);
}
// 主题:订单服务
public class OrderService {
private final List<OrderEventListener> listeners = new ArrayList<>();
public void addListener(OrderEventListener listener) {
listeners.add(listener);
}
public void createOrder(Order order) {
// 核心业务逻辑
saveOrder(order);
// 通知所有观察者
listeners.forEach(l -> l.onOrderCreated(order));
}
}
// 具体观察者
public class InventoryListener implements OrderEventListener {
@Override
public void onOrderCreated(Order order) {
// 扣减库存
}
}
public class NotificationListener implements OrderEventListener {
@Override
public void onOrderCreated(Order order) {
// 发送通知
}
}
Spring 事件机制(推荐)
Spring 内置事件机制,天然支持发布订阅,解耦更彻底。
Spring Event 发布订阅
// 1. 定义事件
public class OrderCreatedEvent extends ApplicationEvent {
private final Order order;
public OrderCreatedEvent(Object source, Order order) {
super(source);
this.order = order;
}
public Order getOrder() { return order; }
}
// 2. 发布事件
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;
public void createOrder(Order order) {
saveOrder(order);
publisher.publishEvent(new OrderCreatedEvent(this, order));
}
}
// 3. 监听事件
@Component
public class InventoryEventListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 扣减库存
}
}
@Component
public class NotificationEventListener {
@Async // 异步处理,不阻塞主流程
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 发送通知
}
}
优势
- 发布者和监听者完全解耦,互不感知
@Async可异步执行,不影响主流程- 新增监听者只需加一个
@EventListener方法
常见面试问题
Q1: Spring 事件机制默认是同步还是异步?
答案:
默认是同步的。publishEvent() 会依次调用所有监听者,全部执行完才返回。要异步需要在监听方法上加 @Async,并在配置类上启用 @EnableAsync。
Q2: 观察者模式在 Java 中有哪些应用?
答案:
| 场景 | 说明 |
|---|---|
| Spring ApplicationEvent | 最常见的事件驱动实现 |
| Servlet Listener | HttpSessionListener、ServletContextListener |
JDK PropertyChangeListener | JavaBean 属性变化监听 |
| MQ 消息消费 | 消费者监听消息主题 |
Q3: Spring 事件和 MQ 消息的区别?
答案:
| 维度 | Spring Event | MQ |
|---|---|---|
| 作用范围 | 单个 JVM 内 | 跨服务/跨进程 |
| 可靠性 | 进程崩溃丢失 | 持久化保证不丢 |
| 异步 | @Async(单机线程池) | 天然异步 |
| 适用场景 | 服务内部解耦 | 服务间解耦 |