notifyObservers()不触发监听是因为Observable的setChanged()必须手动调用,否则直接返回;JDK9+已弃用,推荐用CopyOnWriteArrayList手写线程安全监听器,注意生命周期管理防内存泄漏。

Java里自己写Observer,为什么notifyObservers()不触发监听?
因为JDK自带的java.util.Observable类是**被设计为final修饰的setChanged()必须手动调用**,否则notifyObservers()直接返回、什么也不做。这不是bug,是它的契约——但没人提醒你这点。
-
setChanged()必须在notifyObservers()前调用,且只对“已标记改变”的对象发通知 - 子类继承
Observable后,如果忘了调用setChanged(),监听器永远收不到事件 - JDK 9+ 中
Observable已被标记为@Deprecated,不建议新项目使用
用java.util.concurrent.CopyOnWriteArrayList手写监听器列表更可靠
替代Observable最常用也最稳妥的方式,是自己维护一个线程安全的监听器集合。选CopyOnWriteArrayList不是因为它快,而是它**迭代时不抛ConcurrentModificationException,允许监听器在回调中移除自己**。
- 监听器注册用
add(),注销用remove(),都线程安全 - 遍历时直接用
for (Listener l : listeners),不用iterator()或增强for以外的写法 - 避免在通知循环里调用
listeners.clear()或new ArrayList(listeners)——多此一举且可能漏通知
private final CopyOnWriteArrayList<DataChangeListener> listeners = new CopyOnWriteArrayList<>();
public void notifyDataChanged(String data) {
for (DataChangeListener l : listeners) {
l.onDataChange(data);
}
}
监听器接口要不要带泛型?看事件参数是否统一
如果整个系统只有一种事件(比如全是String消息),接口不泛型更轻量;但一旦出现UserEvent、ConfigEvent、ErrorEvent多种类型,硬塞进同一个接口会导致大量instanceof和强制转型,反而难维护。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 推荐按事件职责拆接口:
UserEventListener、ConfigEventListener,各自处理明确类型 - 不要为了“统一”而定义
EventListener<T>然后到处传Object——类型擦除后失去校验意义 - 如果真需要泛型抽象,用具体实现类约束类型,而不是在接口上泛化
Spring的@EventListener能直接替换自定义机制吗?
可以,但要注意它依赖Spring容器管理生命周期。如果你的事件发布者不在IoC容器里(比如工具类、静态方法、单元测试中的new实例),@EventListener方法根本不会被扫描到,也不会执行。
立即学习“Java免费学习笔记(深入)”;
-
@EventListener本质是Spring Event机制,底层用ApplicationEventMulticaster分发,不是语言级特性 - 非Spring环境(如Android、Java SE命令行工具)必须手写,别指望注解自动生效
- 混用时注意:自定义发布逻辑 + Spring监听器,要确保事件对象可被Spring序列化(无非static字段、无不可序列化依赖)
removeListener(),比逻辑写错更难排查。

















