观察者模式实战及Spring事件机制实现(附全部代码)

一、为什么要用观察者模式?

观察者模式(Observer Pattern)是一种行为型设计模式,其核心目的是建立对象之间的依赖关系,使得当一个对象(称为主题 / Subject)的状态发生变化时,所有依赖它的对象(称为观察者 / Observer)都能自动收到通知并更新自身状态。其应用场景包括:

  • 事件驱动系统:如 GUI 界面中按钮点击事件的监听。
  • 数据更新通知:如股票价格、天气数据的实时更新推送。
  • 消息订阅系统:如新闻推送、社交平台的关注订阅功能。

二、观察者模型解决的核心问题

1、解耦对象间的依赖关系
主题与观察者之间通过抽象接口交互,主题无需知道具体观察者的实现,观察者也不依赖主题的具体实现。例如,一个天气数据中心(主题)可以向多个应用(观察者)发送数据,而无需关心应用如何展示数据。

2、支持灵活的扩展
新增观察者时,只需实现统一的接口并注册到主题中,无需修改主题的代码。例如,在新闻系统中新增一个推送渠道(如短信通知),只需添加对应的观察者类。

3、实现动态的一对多通信
当主题状态变化时,所有观察者会被自动通知,无需手动逐个更新。例如,股票价格变化时,所有订阅该股票的用户都会收到提醒。

三、观察者模式的优缺点

优点:

  • 高解耦性,主题和观察者彼此独立,双方只需关注自身逻辑,降低了代码耦合度。例如,电商平台的订单系统(主题)更新时,库存系统、物流系统(观察者)可独立更新,互不影响。
  • 良好的可扩展性,新增观察者无需修改现有代码,符合 “开闭原则”。例如,在邮件系统中新增 “未读提醒” 功能,只需添加新的观察者类。
  • 支持广播通信,主题可同时通知所有观察者,适合需要批量更新的场景。例如,服务器状态监控系统中,一个状态变化可通知所有监控终端。
  • 实时性强,状态变化时自动触发通知,适合需要实时响应的场景(如实时聊天、实时数据监控)。

缺点:

  • 潜在的性能问题,若观察者数量过多,主题通知所有观察者可能产生性能开销。例如,股票行情系统若有百万级观察者,一次价格更新可能导致卡顿。
  • 通知顺序不可控,主题无法保证观察者的接收顺序,若观察者之间存在依赖关系,可能导致逻辑错误。例如,A 观察者需要先于 B 观察者更新,但代码中无法强制顺序。
  • 循环依赖风险,若观察者反向修改主题状态,可能导致循环通知(如 A 更新触发 B,B 更新又触发 A),引发系统崩溃。

四、观察者模式实战

4.1 场景:

有个网站,当发布系统公告时需要通知到管理员和用户,使用观察者模式和Spring事件机制实现。

4.2 观察者模式实现

主题:


public interface Subject {

    void registerObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObservers();
}

观察者:


public interface Observer {
    void update(String msg);
}

通知:


import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class Notice implements Subject {
    private static final List<Observer> OBSERVERS = new CopyOnWriteArrayList<>();
    private String msg;

    public Notice() {
    }

    public Notice(Observer observer) {
        registerObserver(observer);
    }

    @Override
    public void registerObserver(Observer observer) {
        OBSERVERS.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        OBSERVERS.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : OBSERVERS) {
            observer.update(msg);
        }
    }

    public void sendMsg(String msg) {
        this.msg = msg;
        notifyObservers();
    }
}

管理员(通过实现Spring InitializingBean 接口添加观察者):

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

@Service
public class Admin implements Observer, InitializingBean {

    @Override
    public void afterPropertiesSet() {
        new Notice(this);
    }

    @Override
    public void update(String msg) {
        System.out.println("管理员收到系统公告为:" + msg);
        // 给管理员发送站内消息
    }
}

用户(通过实现Spring InitializingBean 接口添加观察者):

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

@Service
public class User implements Observer, InitializingBean {

    @Override
    public void afterPropertiesSet() {
        new Notice(this);
    }

    @Override
    public void update(String msg) {
        System.out.println("用户收到系统公告为:" + msg);
        // 给用户发送站内消息
    }
}

客户端:


import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/observer")
public class ObserverController {
    @RequestMapping("/send")
    public String send() {
        Notice notice = new Notice();
        notice.sendMsg("测试消息");
        return " 消息发送成功 success";
    }
}

接口请求:
接口请求
结果

4.3 Spring 事件机制实现

消息发送事件定义:


import org.springframework.context.ApplicationEvent;

public class SendMessageEvent extends ApplicationEvent {
    private final String message;

    public SendMessageEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

管理员监听事件:


import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class Administrator implements ApplicationListener<SendMessageEvent> {
    @Override
    public void onApplicationEvent(SendMessageEvent event) {
        String message = event.getMessage();
        System.out.println("ApplicationListener 管理员收到消息:" + message);
    }
}

用户监听事件:


import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class Client implements ApplicationListener<SendMessageEvent> {
    @Override
    public void onApplicationEvent(SendMessageEvent event) {
        String message = event.getMessage();
        System.out.println("ApplicationListener 用户收到消息:" + message);
    }
}

事件发布:


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
public class SendMessageService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void sendMessage(String message) {
        eventPublisher.publishEvent(new SendMessageEvent(this, message));
    }

}

客户端:


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/sendMessage")
public class SendMessageController {
    @Autowired
    private SendMessageService sendMessageService;

    @RequestMapping("/send")
    public String send() {
        sendMessageService.sendMessage("测试消息");
        return "ApplicationListener 测试消息发送成功 success";
    }
}

接口请求:

请求
结果

五、观察者模式与 Spring 事件机制对比解析

5.1、核心概念对比

维度观察者模式Spring 事件机制
定义一种行为设计模式,实现对象间的一对多依赖关系。Spring 框架提供的基于事件的发布 - 订阅模型,是观察者模式的企业级实现。
核心组件主题(Subject)、观察者(Observer)。事件(ApplicationEvent)、发布者(ApplicationEventPublisher)、监听器(ApplicationListener)。
触发方式主题主动调用观察者的更新方法。通过 ApplicationEventPublisher 发布事件,由 Spring 容器管理事件传播。
耦合度需手动维护观察者注册 / 注销,代码耦合度较高。基于接口和注解,依赖 Spring 容器,耦合度低。

5.2 使用场景对比

场景观察者模式Spring 事件机制
GUI 事件处理原生实现(如 Java AWT/Swing)不适用(Spring 不直接处理 GUI)
系统模块间解耦需手动实现,适用于简单场景推荐使用,通过事件隔离业务逻辑
异步事件处理需自行实现线程池,复杂度高。支持 @Async 注解,简单易用。
跨服务事件通知不支持远程通信结合 Spring Cloud Bus 可实现分布式事件
事务管理无法与事务绑定支持 @TransactionalEventListener,确保事件与事务同步

5.3、优缺点对比

观察者模式:

优点:

  • 实现简单,无需依赖外部框架。
  • 轻量级,适用于小型项目。

缺点:

  • 手动管理观察者,代码冗余。
  • 事件传播阻塞主线程,性能较差。
  • 缺乏统一管理,扩展性有限。

Spring 事件机制

优点:

  • 依赖注入简化开发,降低耦合。
  • 支持异步、事务性事件,功能丰富。
  • 与 Spring 生态无缝集成(如 AOP、缓存)。

缺点:

  • 依赖 Spring 容器,无法独立使用。
  • 事件定义和监听逻辑分散,调试复杂度较高。




– 欢迎点赞、关注、转发、收藏【技术咖啡馆C】,各大平台同名。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

技术咖啡馆C

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

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

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

打赏作者

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

抵扣说明:

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

余额充值