跳到主要内容

观察者模式

问题

什么是观察者模式?和发布-订阅模式有什么区别?Spring 中如何使用事件机制?

答案

核心思想

定义对象间的一对多依赖关系:当一个对象(Subject)状态改变时,所有依赖它的对象(Observer)自动收到通知并更新。

观察者 vs 发布订阅

维度观察者模式发布订阅模式
耦合度Subject 直接持有 Observer 引用通过事件中心/消息中间件解耦
通信方式同步调用可以异步
典型实现JDK Observer、Guava EventBusSpring 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 ListenerHttpSessionListenerServletContextListener
JDK PropertyChangeListenerJavaBean 属性变化监听
MQ 消息消费消费者监听消息主题

Q3: Spring 事件和 MQ 消息的区别?

答案

维度Spring EventMQ
作用范围单个 JVM 内跨服务/跨进程
可靠性进程崩溃丢失持久化保证不丢
异步@Async(单机线程池)天然异步
适用场景服务内部解耦服务间解耦

相关链接