Java 内置观察者模式一、基础概念观察者模式属于行为型设计模式核心思想一对多依赖关系一个目标被观察者/主题状态发生变化时自动通知所有订阅它的观察者观察者收到通知后执行自身更新逻辑二者解耦。Java 早期 JDK 直接提供了一套原生 API 实现观察者模式位于java.util包下由两个核心类/接口构成java.util.Observable被观察者主题、发布者抽象父类类非接口java.util.Observer观察者函数式接口⚠️ 重要前提Java 9 开始被标记为Deprecated过时废弃官方不再推荐使用。二、两大核心组件详解1. Observer 观察者接口FunctionalInterfacepublicinterfaceObserver{/** * 被观察者状态变更回调此方法通知观察者 * param o 触发通知的被观察者对象 * param arg 推送携带的自定义参数可选 */voidupdate(Observableo,Objectarg);}函数式接口可以直接用 Lambda 简写实现所有观察者必须实现该接口重写update()接收消息推送2. Observable 被观察者主题是一个普通类不能多继承内部维护了观察者集合提供订阅、取消订阅、状态变更通知全套方法核心成员变量// 存放所有已订阅的观察者线程安全容器privatefinalVectorObserverobs;// 标记被观察者自身状态是否发生改变privatebooleanchangedfalse;常用核心方法方法作用void addObserver(Observer o)订阅添加观察者到集合void deleteObserver(Observer o)取消订阅移除指定观察者void deleteObservers()清空所有观察者int countObservers()获取当前订阅的观察者数量protected void setChanged()关键标记自身状态已修改只有标记后才会执行通知protected void clearChanged()清除状态变更标记boolean hasChanged()查询是否标记了状态变更void notifyObservers()无参推送通知所有观察者argnullvoid notifyObservers(Object arg)带参数推送携带数据传给观察者update方法通知执行流程业务修改被观察者数据 → 调用setChanged()打上变更标记调用notifyObservers()内部遍历所有观察者挨个调用observer.update(this, 参数)通知完毕自动调用clearChanged()清空标记三、完整代码示例手把手演示场景公众号被观察者发布文章订阅用户观察者收到推送通知importjava.util.Observable;importjava.util.Observer;// 1. 自定义被观察者公众号classOfficialAccountextendsObservable{// 发布文章方法publicvoidpublishArticle(Stringcontent){System.out.println(公众号发布新文章content);// 第一步标记状态发生改变必须调用否则不会推送通知setChanged();// 第二步推送消息给所有订阅者携带文章内容notifyObservers(content);}}// 2. 测试主类publicclassObserverDemo{publicstaticvoidmain(String[]args){// 创建被观察者OfficialAccountaccountnewOfficialAccount();// 观察者1用户AObserveruserA(obs,arg)-{System.out.println(用户A收到推送新文章 - arg);};// 观察者2用户BObserveruserB(obs,arg)-{System.out.println(用户B收到推送新文章 - arg);};// 订阅account.addObserver(userA);account.addObserver(userB);// 发布文章触发通知account.publishArticle(Java观察者模式详解);System.out.println(用户B取消订阅后);// 取消订阅account.deleteObserver(userB);account.publishArticle(Spring源码阅读笔记);}}运行结果公众号发布新文章Java观察者模式详解 用户B收到推送新文章 - Java观察者模式详解 用户A收到推送新文章 - Java观察者模式详解 用户B取消订阅后 公众号发布新文章Spring源码阅读笔记 用户A收到推送新文章 - Spring源码阅读笔记四、JDK内置实现的优缺点优点开箱即用无需自己维护观察者集合、订阅/取消订阅、通知遍历逻辑代码极简自带状态变更标记机制可灵活控制什么时候推送消息自带线程安全底层Vector基础多线程场景不用自己加锁致命缺点也是被废弃的根本原因Observable是类不是接口违反面向接口编程Java是单继承如果你的业务类已经继承了其他父类就无法再继承Observable扩展性极差。无法自定义通知顺序、通知策略内部遍历Vector有序推送不能调整观察者回调顺序同步阻塞推送一个观察者耗时过长会阻塞后续所有观察者。耦合度偏高被观察者、观察者都强依赖JDK util包内置类不方便替换实现。无法精细控制通知粒度只能全体推送不支持按话题分组订阅类似MQ的主题订阅。线程模型单一默认同步调用没有异步通知能力。五、为什么 Java 9 废弃这套API设计缺陷Observable作为具体类继承限制太大不符合开闭原则功能简陋不支持异步、分组订阅、事件类型区分官方推荐替代方案小型场景自己手写观察者模式自定义主题接口观察者接口企业级开发使用事件驱动框架Guava EventBus、Spring 事件监听ApplicationEvent、RxJava、消息队列(RabbitMQ/Kafka)六、对比手写观察者 vs JDK内置JDK内置省事但受继承约束、扩展性差手写自定义自己定义Subject主题接口、Observer观察者接口任意类都能实现自由度最高日常开发首选。七、拓展Spring中的事件监听观察者模式最佳实践Spring框架基于观察者思想封装了事件机制彻底规避了JDK原生的所有问题ApplicationEvent事件消息载体ApplicationEventPublisher发布者被观察者ApplicationListener事件监听者观察者支持异步监听、条件监听、注解驱动EventListener是Java后端最常用的观察者落地方案。