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

发布于:2025-06-02 ⋅ 阅读:(26) ⋅ 点赞:(0)

一、观察者模式场景

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 {
    @Override
    public 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<>();

    @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

// 配置中心变更事件
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 注解驱动增强

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


网站公告

今日签到

点亮在社区的每一天
去签到