Java观察者模式事件通知如何实现

wen java案例 4

Java观察者模式事件通知实现全解析:从原理到实战

目录导读

  1. 观察者模式核心概念
  2. Java原生实现方式
  3. 基于事件监听的进阶实现
  4. Spring框架中的事件机制
  5. 性能优化与常见陷阱
  6. FAQ:高频问题解答

观察者模式核心概念

问答环节
Q:观察者模式解决了什么问题?
A:解决对象间一对多的依赖关系——当一个对象状态变化时,所有依赖它的对象自动收到通知并更新,典型场景包括:GUI事件监听、消息推送、分布式系统状态同步。

Java观察者模式事件通知如何实现

模式三要素

  • 主体(Subject):维护观察者列表,提供注册/删除接口
  • 观察者(Observer):定义更新接口
  • 具体实现:Event(事件对象)作为通知载体

设计原则
遵循开放封闭原则(对扩展开放,对修改封闭)和依赖倒置原则(面向接口编程)。


Java原生实现方式

1 基于java.util.Observable和Observer

// 被观察者
public class WeatherData extends Observable {
    private float temperature;
    public void setTemperature(float temp) {
        this.temperature = temp;
        setChanged(); // 标记状态已改变
        notifyObservers(temp); // 推送数据
    }
}
// 观察者
public class DisplayBoard implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        float temp = (float) arg;
        System.out.println("温度更新至:" + temp);
    }
}

注意:Java 9后该类标记为Deprecated,推荐使用PropertyChangeListener。

2 自定义纯接口实现

// 事件类
public class TemperatureEvent {
    private final float value;
    // 构造器、getter...
}
// 观察者接口
public interface TemperatureObserver {
    void onTemperatureChange(TemperatureEvent event);
}
// 可观察者接口
public interface Observable {
    void addObserver(TemperatureObserver o);
    void removeObserver(TemperatureObserver o);
    void notifyObservers(TemperatureEvent e);
}

优势:完全控制实现细节,避免JDK内置类的线程安全问题。


基于事件监听的进阶实现

1 使用EventObject + EventListener

// 定义事件
public class DataChangeEvent extends EventObject {
    private final Object newData;
    public DataChangeEvent(Object source, Object newData) {
        super(source);
        this.newData = newData;
    }
}
// 定义监听器接口
public interface DataChangeListener extends EventListener {
    void onDataChanged(DataChangeEvent event);
}
// 实现事件源
public class DataSource {
    private final List<DataChangeListener> listeners = new ArrayList<>();
    public void addListener(DataChangeListener listener) {
        listeners.add(listener);
    }
    public void updateData(Object data) {
        // 业务逻辑
        fireEvent(new DataChangeEvent(this, data));
    }
    private void fireEvent(DataChangeEvent event) {
        listeners.forEach(l -> l.onDataChanged(event));
    }
}

2 异步通知实现

// 使用线程池异步通知
private final ExecutorService executor = Executors.newCachedThreadPool();
private void fireEventAsync(DataChangeEvent event) {
    listeners.forEach(l -> executor.submit(() -> l.onDataChanged(event)));
}

性能要点:同步通知可能阻塞主流程,异步需注意线程安全。


Spring框架中的事件机制

1 Spring事件三要素

  • Event:继承ApplicationEvent
  • Publisher:注入ApplicationEventPublisher
  • Listener:使用@EventListener注解
// 事件
public class OrderCreatedEvent extends ApplicationEvent {
    private final Long orderId;
    public OrderCreatedEvent(Object source, Long orderId) {
        super(source);
        this.orderId = orderId;
    }
}
// 发布
@Component
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;
    public void createOrder() {
        // 业务逻辑
        publisher.publishEvent(new OrderCreatedEvent(this, 1001L));
    }
}
// 监听
@Component
public class NotificationListener {
    @EventListener
    @Async // 异步执行
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("订单" + event.getOrderId() + "已创建,发送通知");
    }
}

2 Transactional事件监听

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(OrderCreatedEvent event) {
    // 事务提交后执行
}

优势:与Spring事务集成,避免脏数据问题。


性能优化与常见陷阱

1 性能优化策略

  • 弱引用观察者:避免内存泄漏
    private final List<WeakReference<Observer>> observers = new ArrayList<>();
  • 批量通知:合并高频事件
  • 事件过滤:使用topic/type字段区分事件类型

2 常见陷阱

  1. 循环通知:A监听B,B又监听A,导致无限递归
    解决方案:使用事件序号或状态检查
  2. 观察者抛出异常:导致后续观察者无法收到通知
    解决方案:捕获异常继续传播
  3. 线程安全问题:多线程同时注册/删除观察者
    解决方案:使用CopyOnWriteArrayList或synchronized块

FAQ:高频问题解答

Q1:观察者模式和发布订阅模式有什么区别?
A:观察者模式是直接通信(Subject维护Observer列表),发布订阅模式通过事件通道解耦(Publisher和Subscriber不直接感知),RabbitMQ/Kafka属于发布订阅。

Q2:JDK内置观察者模式为什么被废弃?
A:Observable是类而非接口,违反单一职责;序列化支持差;事件通知缺少泛型支持,推荐使用PropertyChangeSupport或自定义接口。

Q3:Spring @EventListener和@TransactionalEventListener有何不同?
A:后者绑定事务生命周期,可指定在提交前/后、回滚后等阶段执行,防止事务未提交时访问数据库造成的不一致性。

Q4:如何实现观察者优先级?
A:使用有序集合如PriorityBlockingQueue,或为观察者标记order属性,通知前排序。

Q5:生产环境中如何监控事件通知链路?
A:使用AOP切面记录事件发布/处理的耗时,结合Micrometer指标暴露,搭配Prometheus监控,或使用分布式追踪如Zipkin。


Java观察者模式的事件通知实现从原生JDK到Spring框架,已形成完整生态,核心在于解耦扩展性,实际开发中建议优先选择Spring事件机制(集成事务、异步支持),对于轻量级场景采用自定义接口实现,注意线程安全和内存管理,才能构建健壮的事件驱动系统。

上一篇Java责任链模式请求依次处理

下一篇当前分类已是最新一篇

抱歉,评论功能暂时关闭!