当前位置: 首页 > backend >正文

设计模式:观察者模式 - 实战

一、观察者模式场景

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隔离异常观察者

http://www.xdnf.cn/news/9759.html

相关文章:

  • MATLAB中的table数据类型:高效数据管理的利器
  • OCC笔记:面、边的方向(TopAbs_Orientation)
  • Triton推理服务器部署YOLOv8(onnxruntime后端和TensorRT后端)
  • C++哈希
  • GitHub Copilot 使用手册与原理解析
  • 80x86CPU入栈与出栈操作
  • C++:lambda匿名函数
  • 【VSCode-Qt】Docker远程连接的项目UI文件在 VSCode 上无法预览
  • STM32F407VET6学习笔记8:UART5串口接收中断的Cubemx配置
  • Spring 面经
  • PnP(Perspective-n-Point)算法 | 用于求解已知n个3D点及其对应2D投影点的相机位姿
  • 5.LoadBalancer负载均衡服务调用
  • 【测试】Bug和用例
  • 视觉分析开发范例:Puppeteer截图+计算机视觉动态定位
  • 国内连接速度较快的常用 Yum 源及其具体配置方法
  • mysql一主多从 k8s部署实际案例
  • 【C++项目】:仿 muduo 库 One-Thread-One-Loop 式并发服务器
  • 什么是VR全景相机?如何选择VR全景相机?
  • http传输协议的加密
  • 黑马点评项目02——商户查询缓存(缓存穿透、缓存雪崩、缓存击穿)以及细节
  • 有关于常量的一节知识
  • JAVA学习 DAY1 初识JAVA
  • 生成式引擎的认知霸权:为什么传统内容失效?
  • 【AI非常道】二零二五年三月,AI非常道
  • 黑马程序员C++核心编程笔记--1 程序的内存模型
  • AniGS - 基于单张图像的动态高斯化身重建
  • 62、【OS】【Nuttx】编码规范解读(十)
  • 电缆中性点概念
  • webstrorm 提示(This file does not belong to the project)此文件不属于该项目
  • 深度学习-模型训练的相关概念