设计模式:观察者模式 - 实战
一、观察者模式场景
1.1 什么是观察者模式?
观察者模式(Observer Pattern)观察者模式是一种行为型设计模式,用于定义一种一对多的依赖关系,当对象的状态发生变化时,所有依赖于它的对象都会自动收到通知并更新。
核心思想观察者模式实现了对象之间的解耦:被观察者(Subject)专注于自身状态的管理,而观察者(Observer)专注于对状态变化的响应,二者通过通知机制进行交互
1.2 传统开发模式的三大死穴
强耦合陷阱:订单状态变更需要手动调用10+通知服务(邮件/SMS/物流…)
扩展噩梦:新增通知渠道必须修改核心业务代码(违反OCP原则)
性能瓶颈:同步调用链导致接口响应时间突破2秒红线
1.3 观察者模式的破局之道
事件驱动架构:业务逻辑与事件处理物理隔离
动态扩展能力:新增观察者零侵入核心系统
异步削峰:实测QPS提升300%(订单支付场景)
1.4 优点
解耦:被观察者和观察者之间的耦合度低,便于扩展。
动态联动:可以动态添加、移除观察者,灵活性强。
符合开闭原则:被观察者的状态变化通知机制对扩展开放,对修改关闭。
1.5 缺点
性能问题:观察者过多时,通知机制可能导致性能开销。
复杂性增加:过多的观察者与被观察者关系可能增加系统的复杂性。
可能产生循环依赖:若观察者与被观察者相互依赖,可能导致循环调用。
1.6 应用场景
事件驱动模型:如 UI 事件监听器(按钮点击等)。
发布-订阅机制:消息队列、事件总线等。
状态同步:某一对象的状态变化需要通知多个依赖对象时。
二、技术方案设计
2.1 架构演进对比
2.2 核心组件设计
[事件源] --发布--> [EventBus] --通知--> [观察者集群]↑ ↖[事件对象] [线程池分发]
三、Java原生实现
3.1 基于JDK的经典实现
// 支付成功事件定义
public class PaymentSuccessEvent extends EventObject {private final String orderId;private final BigDecimal amount;public PaymentSuccessEvent(Object source, String orderId, BigDecimal amount) {super(source);this.orderId = orderId;this.amount = amount;}
}// 支付服务(事件源)
public class PaymentService {private final List<EventListener> listeners = new CopyOnWriteArrayList<>();public void addListener(EventListener listener) {listeners.add(listener);}public void pay(String orderId, BigDecimal amount) {// 支付核心逻辑...notifyListeners(new PaymentSuccessEvent(this, orderId, amount));}private void notifyListeners(PaymentSuccessEvent event) {listeners.forEach(listener -> listener.onEvent(event));}
}// 邮件通知观察者
public class EmailNotifier implements EventListener {@Overridepublic void onEvent(EventObject event) {if (event instanceof PaymentSuccessEvent) {PaymentSuccessEvent e = (PaymentSuccessEvent) event;sendEmail(e.getOrderId(), e.getAmount());}}
}
3.2 Java9+改进方案
// 使用Flow API实现响应式流
public class PaymentPublisher implements Flow.Publisher<PaymentEvent> {private final Executor executor = ForkJoinPool.commonPool();private final List<Flow.Subscriber<? super PaymentEvent>> subscribers = new CopyOnWriteArrayList<>();@Overridepublic void subscribe(Flow.Subscriber<? super PaymentEvent> subscriber) {subscribers.add(subscriber);subscriber.onSubscribe(new PaymentSubscription(subscriber));}private class PaymentSubscription implements Flow.Subscription {private final Flow.Subscriber<? super PaymentEvent> subscriber;PaymentSubscription(Flow.Subscriber<? super PaymentEvent> subscriber) {this.subscriber = subscriber;}@Overridepublic void request(long n) {// 背压处理}@Overridepublic void cancel() {subscribers.remove(subscriber);}}
}
四、Spring生态进阶实现
4.1 基于ApplicationEvent
// 配置中心变更事件
public class ConfigUpdateEvent extends ApplicationEvent {private final String configKey;private final String newValue;public ConfigUpdateEvent(Object source, String configKey, String newValue) {super(source);this.configKey = configKey;this.newValue = newValue;}
}// 动态配置观察者
@Component
public class ConfigRefreshListener {@EventListener@Asyncpublic void handleConfigUpdate(ConfigUpdateEvent event) {refreshConfigCache(event.getConfigKey(), event.getNewValue());notifyAllServers(event);}
}// 事件发布
@Service
public class ConfigService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void updateConfig(String key, String value) {// 更新数据库eventPublisher.publishEvent(new ConfigUpdateEvent(this, key, value));}
}
4.2 注解驱动增强
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BusinessEventListener {String[] keys() default {};EventMode mode() default EventMode.ASYNC;
}// AOP切面处理
@Aspect
@Component
public class EventListenerAspect {@Around("@annotation(listener)")public Object processEvent(ProceedingJoinPoint pjp, BusinessEventListener listener) {EventObject event = (EventObject) pjp.getArgs()[0];if (shouldHandle(event, listener.keys())) {return switch (listener.mode()) {case ASYNC -> CompletableFuture.runAsync(() -> proceed(pjp));case TRANSACTIONAL -> executeInTransaction(pjp);default -> proceed(pjp);};}return null;}
}
五、生产级优化方案
5.1 性能优化策略
5.2 可靠性保障
// 事件持久化方案
public class PersistentEventBus {private final EventStoreRepository eventStore;@Transactional(propagation = Propagation.REQUIRES_NEW)public void publishWithPersistence(DomainEvent event) {eventStore.save(event);realPublish(event);}// 定时补偿任务@Scheduled(fixedRate = 60000)public void retryFailedEvents() {eventStore.findFailedEvents().forEach(event -> {try {realPublish(event);event.markAsSent();} catch (Exception e) {event.recordRetry();}});}
}
六、经典应用场景
6.1 电商订单系统
支付成功事件 → 库存扣减/物流触发/积分发放使用「发布-确认-补偿」机制保证最终一致性
6.2 微服务配置中心
配置变更事件 → 所有服务实例动态刷新结合Spring Cloud Bus实现集群通知
6.3 物联网数据采集
设备状态事件 → 实时监控/预警分析/大屏展示采用MQTT协议实现百万级设备连接
七、避坑指南
7.1 常见问题排查
内存泄漏:
检查观察者是否及时取消注册
使用WeakReference包装监听器
事件丢失:
增加本地事件持久化层
实现至少一次投递语义
循环触发:
在事件对象中添加traceId
设置最大传播深度阈值
7.2 生产注意事项
事件版本控制:使用Avro Schema管理事件格式
监控埋点:统计事件处理耗时/成功率
熔断降级:Hystrix隔离异常观察者