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

一、观察者模式场景

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 核心组件设计

java 复制代码
[事件源] --发布--> [EventBus] --通知--> [观察者集群]
          ↑                    ↖
       [事件对象]               [线程池分发]

三、Java原生实现

3.1 基于JDK的经典实现

java 复制代码
// 支付成功事件定义
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 {
    @Override
    public void onEvent(EventObject event) {
        if (event instanceof PaymentSuccessEvent) {
            PaymentSuccessEvent e = (PaymentSuccessEvent) event;
            sendEmail(e.getOrderId(), e.getAmount());
        }
    }
}

3.2 Java9+改进方案

java 复制代码
// 使用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<>();

    @Override
    public 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;
        }

        @Override
        public void request(long n) {
            // 背压处理
        }

        @Override
        public void cancel() {
            subscribers.remove(subscriber);
        }
    }
}

四、Spring生态进阶实现

4.1 基于ApplicationEvent

java 复制代码
// 配置中心变更事件
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
    @Async
    public void handleConfigUpdate(ConfigUpdateEvent event) {
        refreshConfigCache(event.getConfigKey(), event.getNewValue());
        notifyAllServers(event);
    }
}

// 事件发布
@Service
public class ConfigService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void updateConfig(String key, String value) {
        // 更新数据库
        eventPublisher.publishEvent(new ConfigUpdateEvent(this, key, value));
    }
}

4.2 注解驱动增强

java 复制代码
@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 可靠性保障

java 复制代码
// 事件持久化方案
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 电商订单系统

java 复制代码
支付成功事件 → 库存扣减/物流触发/积分发放

使用「发布-确认-补偿」机制保证最终一致性

6.2 微服务配置中心

java 复制代码
配置变更事件 → 所有服务实例动态刷新

结合Spring Cloud Bus实现集群通知

6.3 物联网数据采集

java 复制代码
设备状态事件 → 实时监控/预警分析/大屏展示

采用MQTT协议实现百万级设备连接

七、避坑指南

7.1 常见问题排查
内存泄漏:

检查观察者是否及时取消注册

使用WeakReference包装监听器

事件丢失:

增加本地事件持久化层

实现至少一次投递语义

循环触发:

在事件对象中添加traceId

设置最大传播深度阈值

7.2 生产注意事项

事件版本控制:使用Avro Schema管理事件格式

监控埋点:统计事件处理耗时/成功率

熔断降级:Hystrix隔离异常观察者

相关推荐
怡人蝶梦1 小时前
Java后端技术栈问题排查实战:Spring Boot启动慢、Redis缓存击穿与Kafka消费堆积
java·jvm·redis·kafka·springboot·prometheus
瓯雅爱分享1 小时前
MES管理系统:Java+Vue,含源码与文档,实现生产过程实时监控、调度与优化,提升制造企业效能
java·mysql·vue·软件工程·源代码管理
庄小焱2 小时前
设计模式——原型设计模式(创建型)
设计模式
鬼多不菜2 小时前
一篇学习CSS的笔记
java·前端·css
深色風信子2 小时前
Eclipse 插件开发 5.3 编辑器 监听输入
java·eclipse·编辑器·编辑器 监听输入·插件 监听输入
庄小焱3 小时前
设计模式——适配器设计模式(结构型)
设计模式
Blossom.1183 小时前
人工智能在智能健康监测中的创新应用与未来趋势
java·人工智能·深度学习·机器学习·语音识别
shangjg33 小时前
Kafka 如何保证不重复消费
java·分布式·后端·kafka
无处不在的海贼3 小时前
小明的Java面试奇遇之互联网保险系统架构与性能优化
java·面试·架构