14、(行为型设计模式)Java 观察者模式深度学习指南

以下是为你精心撰写的 《Java 观察者模式深度学习指南》,专为 Java 后端开发者打造,内容涵盖:定义、作用、与事件驱动架构的深度对比、真实业务场景、JDK 原生实现、Spring 事件机制、Reactive 响应式演进、避坑指南、最佳实践、面试高频题,所有示例均含中文注释,可直接用于项目重构、异步解耦、消息通知、日志采集、系统监控等核心场景。


📘 Java 观察者模式深度学习指南

—— 从“主动轮询”到“事件驱动”的架构革命

作者:Java 后端架构实战导师
适用对象:Java 后端开发者(Spring Boot / 微服务 / 异步系统 / 消息队列 / 监控系统)
目标:彻底掌握“一个对象状态改变,自动通知所有依赖它的对象”的核心模式,告别“循环调用”和“紧耦合”
核心原则“我不是通知你,我只说‘我变了’,你爱听不听。”


✅ 一、什么是观察者模式?

📌 定义:

观察者模式(Observer Pattern) 是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象(主题 / Subject)的状态发生改变时,所有依赖它的对象(观察者 / Observer)都会自动收到通知并更新

🔍 核心思想:

  • 主题(Subject):被观察的对象,维护一个观察者列表
  • 观察者(Observer):依赖主题的对象,实现更新接口
  • 松耦合通信:主题不知道观察者是谁,只负责“通知”
  • 自动通知:主题状态变化 → 自动调用所有观察者的 update() 方法
  • 动态注册:观察者可以随时添加或移除

💡 一句话记忆
“我不是打电话告诉你,我发个朋友圈,你关注我,自然就看到了。”

🆚 观察者模式 vs 轮询(Polling)

方式轮询(Polling)观察者模式
机制主动频繁查询“有没有变化”被动等待“有变化就通知”
效率低(即使没变化也查)高(只在变化时触发)
实时性延迟高(取决于轮询间隔)实时(变化即通知)
耦合度高(调用方知道被调用方)低(主题和观察者互不依赖)
资源消耗高(CPU、网络)低(仅触发时消耗)
典型场景旧系统、简单脚本现代系统、事件驱动

经典比喻
你订阅了“苹果发布会”:

  • 轮询:你每分钟刷新一次官网看有没有更新 → 浪费流量和时间
  • 观察者:苹果官网发布时,自动给你发邮件/短信 → 高效、精准、及时

✅ 二、观察者模式有什么作用?(Why Use Observer Pattern?)

作用说明
实现松耦合主题和观察者完全解耦,可独立演化
支持一对多通信一个主题可通知多个观察者,无需修改主题代码
提高系统响应性状态变化立即触发,无需轮询延迟
支持广播机制一次通知,多个模块响应(如日志、缓存、通知)
支持异步解耦可将通知放入线程池、消息队列,实现异步处理
提高可扩展性新增观察者只需注册,无需修改主题
符合开闭原则新增观察者不修改主题代码
支撑事件驱动架构(EDA)是现代微服务、消息系统、响应式编程的基础

💡 经典名言
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified automatically.
——《Design Patterns: Elements of Reusable Object-Oriented Software》


✅ 三、观察者模式的典型使用场景(Java 后端真实案例)

场景说明是否推荐使用观察者模式
订单创建后发送通知创建订单 → 发短信、发邮件、记日志、更新积分✅ 强烈推荐
用户注册后激活账户注册成功 → 发验证码、发欢迎邮件、推送APP消息✅ 强烈推荐
缓存失效更新数据库更新 → 清除Redis缓存✅ 强烈推荐
系统监控告警CPU > 90% → 发钉钉、发邮件、触发自动扩容✅ 推荐
审计日志记录所有写操作 → 自动记录操作人、时间、IP✅ 推荐
数据同步主库更新 → 同步到ES、Kafka、HBase✅ 推荐
配置变更通知Nacos配置更新 → 刷新本地缓存、重启服务✅ 推荐
支付成功通知支付成功 → 更新订单状态、通知商户、发放优惠券✅ 推荐
前端WebSocket推送后端事件触发 → 推送给所有在线用户✅ 推荐
简单状态查询获取用户余额❌ 直接调用方法
同步业务调用下单 → 扣库存 → 扣库存必须同步完成❌ 用事务或同步调用
单点通知只有一个观察者,且必须同步❌ 直接调用更简单

判断标准
“一个事件发生后,需要通知多个无关模块,且这些模块不需要立即阻塞等待?”
→ 是 → 用观察者模式!


✅ 四、观察者模式的三种实现方式详解(含中文注释)

我们从JDK 原生实现Spring 事件机制,再到Reactive 响应式演进,逐步深入。


🔹 1. JDK 原生观察者模式(java.util.Observable + Observer

⚠️ 注意:Observable 已过时,不推荐在新项目中使用,但理解其原理很重要。

import java.util.Observable;
import java.util.Observer;

/**
 * 【1】主题(被观察者)—— 继承 Observable
 */
class OrderService extends Observable {
    private String orderId;

    public void createOrder(String orderId) {
        this.orderId = orderId;
        System.out.println("🛒 创建订单:" + orderId);

        // ✅ 关键:通知所有观察者
        setChanged(); // 标记状态已改变
        notifyObservers(orderId); // 传递数据给观察者
    }

    public String getOrderId() {
        return orderId;
    }
}

/**
 * 【2】观察者1:发送短信
 */
class SmsObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        if (arg instanceof String orderId) {
            System.out.println("📱 发送短信:订单 " + orderId + " 已创建");
        }
    }
}

/**
 * 【3】观察者2:发送邮件
 */
class EmailObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        if (arg instanceof String orderId) {
            System.out.println("📧 发送邮件:订单 " + orderId + " 已创建");
        }
    }
}

/**
 * 【4】观察者3:记录日志
 */
class LogObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        if (arg instanceof String orderId) {
            System.out.println("📝 记录日志:订单 " + orderId + " 创建成功");
        }
    }
}

/**
 * 【5】客户端:注册观察者
 */
public class JdkObserverDemo {
    public static void main(String[] args) {
        OrderService orderService = new OrderService();

        // ✅ 注册多个观察者
        orderService.addObserver(new SmsObserver());
        orderService.addObserver(new EmailObserver());
        orderService.addObserver(new LogObserver());

        // ✅ 触发事件:自动通知所有观察者
        orderService.createOrder("ORD20240501");

        // 输出:
        // 🛒 创建订单:ORD20240501
        // 📱 发送短信:订单 ORD20240501 已创建
        // 📧 发送邮件:订单 ORD20240501 已创建
        // 📝 记录日志:订单 ORD20240501 创建成功
    }
}
✅ 优点:
  • JDK 原生支持,无需依赖
  • 简单易懂
❌ 缺点:
  • Observable,不是接口 → 不支持多继承
  • notifyObservers()同步阻塞调用所有观察者
  • 无法传递事件类型,只能传 Object
  • 已被标记为 @Deprecated(Java 9+)

⚠️ 结论仅用于学习,生产环境禁止使用!


🔹 2. 自定义观察者模式(推荐写法)

使用接口 + 集合实现,更灵活、更现代。

import java.util.ArrayList;
import java.util.List;

/**
 * 【1】观察者接口:定义更新方法
 */
interface OrderObserver {
    void onOrderCreated(String orderId);
}

/**
 * 【2】主题:订单服务
 */
class OrderService {
    private List<OrderObserver> observers = new ArrayList<>(); // 维护观察者列表

    public void addObserver(OrderObserver observer) {
        observers.add(observer);
    }

    public void removeObserver(OrderObserver observer) {
        observers.remove(observer);
    }

    public void createOrder(String orderId) {
        System.out.println("🛒 创建订单:" + orderId);

        // ✅ 遍历所有观察者,逐个通知
        for (OrderObserver observer : observers) {
            observer.onOrderCreated(orderId); // 通知
        }
    }
}

/**
 * 【3】观察者1:发送短信
 */
class SmsObserver implements OrderObserver {
    @Override
    public void onOrderCreated(String orderId) {
        System.out.println("📱 发送短信:订单 " + orderId + " 已创建");
    }
}

/**
 * 【4】观察者2:发送邮件
 */
class EmailObserver implements OrderObserver {
    @Override
    public void onOrderCreated(String orderId) {
        System.out.println("📧 发送邮件:订单 " + orderId + " 已创建");
    }
}

/**
 * 【5】观察者3:更新缓存
 */
class CacheObserver implements OrderObserver {
    @Override
    public void onOrderCreated(String orderId) {
        System.out.println("⚡ 清除缓存:订单 " + orderId + " 的缓存已失效");
    }
}

/**
 * 【6】客户端
 */
public class CustomObserverDemo {
    public static void main(String[] args) {
        OrderService orderService = new OrderService();

        // ✅ 注册观察者
        orderService.addObserver(new SmsObserver());
        orderService.addObserver(new EmailObserver());
        orderService.addObserver(new CacheObserver());

        // ✅ 触发事件
        orderService.createOrder("ORD20240501");

        // 输出:
        // 🛒 创建订单:ORD20240501
        // 📱 发送短信:订单 ORD20240501 已创建
        // 📧 发送邮件:订单 ORD20240501 已创建
        // ⚡ 清除缓存:订单 ORD20240501 的缓存已失效
    }
}
✅ 优点:
  • 完全自定义:可定义任意方法名、参数
  • 支持泛型Observer<T>,类型安全
  • 支持异步:可在 onOrderCreated 中开启线程
  • 无 JDK 限制:可被多个类实现
⚠️ 缺点:
  • 同步阻塞:通知是顺序执行,慢的观察者拖慢整体
  • 无错误隔离:一个观察者异常,影响其他观察者
  • 无事件类型:一个方法处理所有事件

🔹 3. 观察者模式 + Spring 事件机制(企业级推荐)

Spring 的 ApplicationEvent + @EventListener观察者模式的最佳实践

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

/**
 * 【1】自定义事件:继承 ApplicationEvent
 */
public class OrderCreatedEvent extends ApplicationEvent {
    private final String orderId;
    private final String userId;

    public OrderCreatedEvent(Object source, String orderId, String userId) {
        super(source);
        this.orderId = orderId;
        this.userId = userId;
    }

    public String getOrderId() {
        return orderId;
    }

    public String getUserId() {
        return userId;
    }
}

/**
 * 【2】主题:订单服务(发布事件)
 */
@Service
public class OrderService {

    @Autowired
    private ApplicationEventPublisher eventPublisher; // ✅ Spring 自动注入

    public void createOrder(String orderId, String userId) {
        System.out.println("🛒 创建订单:" + orderId + ",用户:" + userId);

        // ✅ 发布事件,无需知道谁监听
        eventPublisher.publishEvent(new OrderCreatedEvent(this, orderId, userId));
    }
}

/**
 * 【3】观察者1:发送短信
 */
@Component
public class SmsObserver {

    @EventListener // ✅ 自动监听 OrderCreatedEvent
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("📱 发送短信:订单 " + event.getOrderId() + " 已创建");
    }
}

/**
 * 【4】观察者2:发送邮件
 */
@Component
public class EmailObserver {

    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("📧 发送邮件:订单 " + event.getOrderId() + " 已创建");
    }
}

/**
 * 【5】观察者3:更新缓存(异步)
 */
@Component
public class CacheObserver {

    @EventListener // ✅ 异步监听
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("⚡ 清除缓存:订单 " + event.getOrderId() + " 的缓存已失效");
    }
}

/**
 * 【6】观察者4:记录审计日志(条件监听)
 */
@Component
public class AuditLogObserver {

    @EventListener(condition = "#event.userId == 'admin'") // ✅ 条件监听
    public void handleAdminOrder(OrderCreatedEvent event) {
        System.out.println("📝 审计日志:管理员 " + event.getUserId() + " 创建了订单 " + event.getOrderId());
    }
}

/**
 * 【7】启动类
 */
@SpringBootApplication
public class SpringObserverDemo {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringObserverDemo.class, args);
        OrderService orderService = context.getBean(OrderService.class);

        // ✅ 触发事件:自动通知所有监听者
        orderService.createOrder("ORD20240501", "user123");
        orderService.createOrder("ORD20240502", "admin");

        // 输出:
        // 🛒 创建订单:ORD20240501,用户:user123
        // 📱 发送短信:订单 ORD20240501 已创建
        // 📧 发送邮件:订单 ORD20240501 已创建
        // ⚡ 清除缓存:订单 ORD20240501 的缓存已失效
        //
        // 🛒 创建订单:ORD20240502,用户:admin
        // 📱 发送短信:订单 ORD20240502 已创建
        // 📧 发送邮件:订单 ORD20240502 已创建
        // ⚡ 清除缓存:订单 ORD20240502 的缓存已失效
        // 📝 审计日志:管理员 admin 创建了订单 ORD20240502
    }
}
✅ 优点:
  • 完全解耦:发布者和监听者无直接依赖
  • 注解驱动@EventListener 自动注册
  • 支持异步:加 @Async 实现异步通知
  • 支持条件监听condition = "#event.userId == 'admin'" 灵活过滤
  • 支持泛型事件:可定义复杂事件结构
  • 支持事务同步/异步@EventListener(phase = Phase.AFTER_COMMIT)
  • Spring 官方推荐:所有 Spring Boot 项目都在用!
⚠️ 注意:
  • 默认是同步阻塞:监听者方法执行慢,会拖慢主线程
  • 异步监听需加 @EnableAsync@Async

开启异步监听

@SpringBootApplication
@EnableAsync // ✅ 启用异步支持
public class SpringObserverDemo { ... }

@Component
public class CacheObserver {
    @Async // ✅ 异步执行
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        // 非阻塞,不影响订单创建流程
        System.out.println("⚡ 异步清除缓存:" + event.getOrderId());
    }
}

🔹 4. 观察者模式 + Reactor 响应式演进(现代 Java)

在高并发、流式处理场景下,使用 Reactor 替代传统观察者。

import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;

import java.util.concurrent.atomic.AtomicLong;

/**
 * 【1】主题:订单流
 */
public class OrderStream {
    private final Flux<String> orderFlux;

    public OrderStream() {
        AtomicLong counter = new AtomicLong(0);
        this.orderFlux = Flux.create(emitter -> {
            while (true) {
                long id = counter.incrementAndGet();
                emitter.next("ORD" + id); // 发送事件
                try {
                    Thread.sleep(1000); // 模拟每秒生成一个订单
                } catch (InterruptedException e) {
                    emitter.error(e);
                    break;
                }
            }
        });
    }

    public Flux<String> getOrderStream() {
        return orderFlux;
    }
}

/**
 * 【2】观察者1:短信通知
 */
class SmsObserver {
    public void subscribeTo(OrderStream stream) {
        stream.getOrderStream()
              .subscribe(orderId -> System.out.println("📱 发送短信:" + orderId));
    }
}

/**
 * 【3】观察者2:日志记录
 */
class LogObserver {
    public void subscribeTo(OrderStream stream) {
        stream.getOrderStream()
              .subscribe(orderId -> System.out.println("📝 记录日志:" + orderId));
    }
}

/**
 * 【4】客户端
 */
public class ReactiveObserverDemo {
    public static void main(String[] args) throws InterruptedException {
        OrderStream stream = new OrderStream();

        // ✅ 注册观察者(订阅者)
        new SmsObserver().subscribeTo(stream);
        new LogObserver().subscribeTo(stream);

        // 运行10秒
        Thread.sleep(10000);
    }
}
✅ 优点:
  • 背压(Backpressure):消费者慢时,生产者自动降速
  • 非阻塞、高并发:基于响应式流(Reactive Streams)
  • 支持链式操作filter()map()flatMap()
  • 现代 Java 标准:Spring WebFlux、RSocket、Kafka Streams 都基于此
⚠️ 缺点:
  • 学习曲线陡峭
  • 适用于高吞吐、流式系统,普通业务不必要

✅ 五、观察者模式 vs 事件驱动架构(EDA)对比

维度观察者模式事件驱动架构(EDA)
范围单进程内跨服务、跨系统
通信方式方法调用消息队列(Kafka/RabbitMQ)
耦合度极低(完全解耦)
可靠性同步,可能丢失持久化、重试、确认
扩展性有限无限(可横向扩展)
典型场景单体应用内通知微服务、分布式系统
实现@EventListener@KafkaListener@RabbitListener

演进关系
观察者模式Spring 事件消息队列(Kafka)
本质都是“发布-订阅”思想,只是通信范围和可靠性不同


✅ 六、观察者模式的避坑指南(Java 后端高频踩坑)

问题原因解决方案
❌ 同步阻塞导致性能差观察者方法执行慢,拖慢主线程✅ 使用 @Async 异步处理
❌ 异常导致通知中断一个观察者抛异常,其他不执行✅ 每个监听器加 try-catch,或使用 @EventListenerfallback
❌ 内存泄漏观察者未注销✅ 在 @PreDestroyDisposableBeanremoveObserver()
❌ 事件循环依赖A 发事件 → B 处理 → B 发事件 → A 处理✅ 设计时避免循环依赖,用事件版本号或去重
❌ 事件命名混乱OrderEventOrderCreatedEventOrderCreateEvent✅ 统一命名规范:{Entity}{Action}Event
❌ 事件数据过大传递整个对象,序列化开销大✅ 只传递必要字段(ID、类型)
❌ 用观察者做同步业务如“扣库存”必须同步完成✅ 用事务或同步调用,观察者只做异步事后处理

✅ 七、学习建议与进阶路径

阶段建议
📚 第一周将你项目中“订单创建后发短信、发邮件”的 if-else 重构为 Spring 事件
📚 第二周@EventListener 实现“缓存自动清除”、“审计日志自动记录”
📚 第三周@Async + @EventListener 实现异步通知,提升接口响应速度
📚 第四周阅读 Spring 源码:ApplicationEventMulticaster 如何实现事件分发?
📚 面试准备准备回答:

“你项目中哪里用了观察者模式?”
“Spring 的 @EventListener 是观察者模式吗?”
“观察者模式和策略模式区别?”
“如何解决观察者模式中的异步和异常问题?” |


✅ 八、观察者模式面试高频题(附答案)

Q1:观察者模式解决了什么问题?

A:解决了“一个对象状态变化,需要通知多个依赖对象”的问题,实现松耦合、自动通知。

Q2:Spring 的 @EventListener 是观察者模式吗?

A:是的!它是观察者模式在 Spring 框架中的注解化实现,发布者发布事件,监听者通过 @EventListener 自动订阅。

Q3:观察者模式和策略模式的区别?

A:

  • 观察者“我变了,通知你们”(一对多)
  • 策略“你选哪个算法”(一对一,客户端选择)
    → 一个是“广播”,一个是“选择”

Q4:如何解决观察者模式中的性能问题?

A:

  1. 使用 @Async 实现异步通知
  2. 每个监听器加 try-catch 防止异常中断
  3. 只传递必要数据,避免序列化大对象
  4. 使用消息队列(Kafka)实现跨进程解耦

Q5:什么时候不该用观察者模式?

A:

  • 通知必须同步完成(如扣库存)
  • 只有一个观察者,且必须立即执行
  • 性能要求极高,且事件频率极低(直接调用更简单)

✅ 九、总结:观察者模式选型决策树

graph TD
    A[需要一个事件触发多个响应吗?] --> B{是否在同一进程?}
    B -->|是| C{是否需要异步?}
    C -->|是| D[用 @Async + @EventListener]
    C -->|否| E[用 @EventListener]
    B -->|否| F[用 Kafka/RabbitMQ 实现事件驱动]

最终推荐

  • 单体应用、异步通知 → ✅ Spring @EventListener + @Async(最优雅)
  • 微服务、跨系统 → ✅ Kafka / RabbitMQ(最可靠)
  • 高并发流式处理 → ✅ Reactor / RxJava(最现代)
  • 绝对不要:JDK Observable、同步阻塞通知、循环依赖

✅ 十、结语:真正的高手,不通知别人,只发布一个信号

你不是在学“观察者模式”,你是在学“如何让系统各模块自主响应,而非被动等待”。

当你看到订单创建后,短信、邮件、缓存、日志、积分、风控自动全部触发,而你只写了一行 publishEvent() 时,你已经掌握了事件驱动的精髓。
当你用 Kafka 实现“支付成功”事件,让 5 个微服务各自消费,互不影响时,你已经是分布式架构师了。

不要为了“用模式”而用模式,
要为了“系统可扩展、可解耦、可响应”而选择它。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙茶清欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值