Skip to content
基础

一句话答案

一对多依赖关系,主题状态改变时通知所有观察者;Spring 的 @EventListener + ApplicationEventPublisher 是观察者实现。

核心要点

观察者模式定义对象间一对多的依赖关系,当一个对象(Subject/主题)状态改变时,所有依赖它的对象(Observer/观察者)都会收到通知并自动更新。

核心角色:

  • Subject(主题/被观察者):维护观察者列表,提供注册/移除/通知方法
  • Observer(观察者):定义 update() 方法,接收主题的通知
java
// 主题接口
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

// 观察者接口
public interface Observer {
    void update(Object data);
}

Spring Event 事件机制(观察者模式的实现):

Spring 提供了完整的事件发布-订阅机制:

java
// 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. 发布事件(Subject 角色)
@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;
    
    public void createOrder(Order order) {
        // 业务逻辑...
        publisher.publishEvent(new OrderCreatedEvent(this, order));
    }
}

// 3. 监听事件(Observer 角色)
@Component
public class SmsNotificationListener {
    @EventListener
    public void onOrderCreated(OrderCreatedEvent event) {
        // 发送短信通知
    }
}

@Component
public class InventoryListener {
    @EventListener
    public void onOrderCreated(OrderCreatedEvent event) {
        // 扣减库存
    }
}

Spring Event 的底层实现:

  1. ApplicationEventPublisher 内部维护一个 ApplicationEventMulticaster
  2. Multicaster 持有所有 ApplicationListener 的列表
  3. 发布事件时,遍历匹配的 Listener 依次调用 onApplicationEvent()
  4. @EventListener 注解通过 EventListenerMethodProcessor 在启动时扫描并注册

同步 vs 异步事件:

  • 默认同步:事件处理在发布者的线程中执行
  • 异步处理:在监听方法上加 @Async + 开启 @EnableAsync

观察者模式的优缺点:

  • 优点:主题和观察者松耦合;支持广播通信;符合开闭原则
  • 缺点:观察者过多时通知耗时;循环依赖风险;同步通知可能阻塞
追问与易错

追问方向:

  • Spring 事件同步还是异步?
  • 发布订阅和观察者区别?
  • Spring 事件有什么局限?

易错点:

  • ❌ Spring 事件等于 MQ——是进程内的
  • ❌ @EventListener 异常影响发布者——默认同步会影响

💡 记忆锚点

微信公众号模式:公众号(Subject)发一篇文章,所有关注者(Observer)同时收到推送。Spring里publishEvent()就是发文章,@EventListener就是关注按钮,默认同步推送、加@Async变异步推送。注意这是进程内广播,跨进程得上MQ。