Spring + 设计模式 (十四) 行为型 - 观察者模式

观察者模式

1. 引言

观察者模式是一种行为型设计模式,其核心思想是一对多依赖 ,当被观察者的状态发生变化时,所有依赖它的观察者会自动收到通知并作出响应。观察者模式关注"事件驱动"与"消息分发",通过定义松耦合的发布-订阅机制,实现了对象之间的低耦合通信。它是现代事件驱动架构(如消息队列、事件总线)的理论基础,广泛应用于异步处理和业务解耦场景。

2. 实际开发中的用途

观察者模式在实际开发中适用于需要动态响应状态变化的场景,特别是在事件驱动架构中发挥重要作用。以下是一些典型的应用场景:

  • 用户行为触发:用户注册后发送欢迎邮件、分配积分、记录日志。
  • 订单处理:下单成功后通知库存系统、推送消息、更新用户积分。
  • 配置变更:系统配置更新后自动刷新缓存或通知相关服务。
  • 实时监控:监控系统检测到异常后触发告警(如邮件、短信)。
  • UI更新:界面组件监听数据变化,自动更新视图(如MVVM框架)。
  • 消息通知:社交平台中用户发布动态后通知所有关注者。

观察者模式通过将核心业务逻辑与后续处理解耦,显著提升了系统的可扩展性和可维护性。它允许开发者在不修改核心流程的情况下,动态添加或移除响应逻辑,符合开闭原则

3. 开发中的示例

以"用户注册"场景为例,假设用户注册成功后需要触发多个动作(如发送欢迎邮件、记录日志、分配积分)。通过观察者模式,我们可以将这些动作封装为独立的观察者,实现逻辑解耦。

java 复制代码
// 观察者接口
public interface UserRegisterObserver {
    void onRegister(String username);
}

// 邮件发送观察者
public class EmailSender implements UserRegisterObserver {
    @Override
    public void onRegister(String username) {
        System.out.println("发送注册成功邮件给用户: " + username);
    }
}

// 日志记录观察者
public class LogRecorder implements UserRegisterObserver {
    @Override
    public void onRegister(String username) {
        System.out.println("记录日志: 用户 " + username + " 注册成功");
    }
}

// 积分分配观察者
public class PointAllocator implements UserRegisterObserver {
    @Override
    public void onRegister(String username) {
        System.out.println("为用户 " + username + " 分配欢迎积分");
    }
}

// 被观察者:注册服务
public class UserRegisterSubject {
    private final List<UserRegisterObserver> observers = new ArrayList<>();

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

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

    public void register(String username) {
        System.out.println("用户 " + username + " 注册成功");
        notifyObservers(username);
    }

    private void notifyObservers(String username) {
        for (UserRegisterObserver observer : observers) {
            observer.onRegister(username);
        }
    }
}

使用示例

java 复制代码
public class Main {
    public static void main(String[] args) {
        UserRegisterSubject subject = new UserRegisterSubject();
        subject.addObserver(new EmailSender());
        subject.addObserver(new LogRecorder());
        subject.addObserver(new PointAllocator());

        subject.register("Alice");
    }
}

输出

makefile 复制代码
用户 Alice 注册成功
发送注册成功邮件给用户: Alice
记录日志: 用户 Alice 注册歩成功
为用户 Alice 分配欢迎积分

在这个例子中,注册服务(被观察者)仅负责核心注册逻辑,观察者负责处理后续动作。如果需要添加新功能(如发送短信通知),只需实现新的观察者并注册,无需修改核心代码。

4. Spring源码中的应用

Spring框架通过ApplicationEventApplicationListener提供了对观察者模式的强大支持,构建了一个高效的发布-订阅机制。这种机制广泛应用于Spring容器的事件处理,如上下文初始化、Bean生命周期管理、异常通知等。

核心组件

  1. ApplicationEvent :表示事件,继承自java.util.EventObject,用于携带事件数据。
  2. ApplicationListener:事件监听器接口,定义了事件处理逻辑。
  3. ApplicationEventPublisher:事件发布器,负责将事件广播给所有相关监听器。
  4. ApplicationEventMulticaster:事件多播器,管理监听器并分发事件,支持同步或异步通知。

Spring事件发布流程

Spring通过AbstractApplicationContextpublishEvent方法发布事件:

java 复制代码
// AbstractApplicationContext.java
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    ApplicationEvent applicationEvent = (event instanceof ApplicationEvent ? 
        (ApplicationEvent) event : new PayloadApplicationEvent<>(this, event));
    if (this.applicationEventMulticaster != null) {
        this.applicationEventMulticaster.multicastEvent(applicationEvent, eventType);
    }
}

ApplicationEventMulticaster负责维护监听器列表并分发事件,支持异步执行(通过配置TaskExecutor)或同步执行。这种设计将事件发布者与监听者完全解耦,体现了观察者模式的精髓。

典型案例

Spring内置了多种事件,如:

  • ContextRefreshedEvent:容器初始化或刷新完成时触发。
  • ContextClosedEvent:容器关闭时触发。
  • RequestHandledEvent:Web请求处理完成时触发。

开发者也可以自定义事件,扩展Spring的事件机制。

5. Spring Boot代码案例

以下是一个基于Spring Boot的完整观察者模式示例,模拟用户注册成功后触发邮件通知、日志记录和积分分配。

java 复制代码
// 1. 自定义事件
public class UserRegisterEvent extends ApplicationEvent {
    private final String username;

    public UserRegisterEvent(Object source, String username) {
        super(source);
        this.username = username;
    }

    public String getUsername() {
        return username;
    }
}

// 2. 事件监听器
@Component
public class EmailNotificationListener implements ApplicationListener<UserRegisterEvent> {
    @Override
    public void onApplicationEvent(UserRegisterEvent event) {
        System.out.println("邮件通知: 欢迎用户 " + event.getUsername() + " 加入我们!");
    }
}

@Component
public class LogRecordListener implements ApplicationListener<UserRegisterEvent> {
    @Override
    public void onApplicationEvent(UserRegisterEvent event) {
        System.out.println("记录日志: 用户 " + event.getUsername() + " 于 " + 
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 注册成功");
    }
}

@Component
public class PointAllocatorListener implements ApplicationListener<UserRegisterEvent> {
    @Override
    public void onApplicationEvent(UserRegisterEvent event) {
        System.out.println("分配积分: 为用户 " + event.getUsername() + " 添加100欢迎积分");
    }
}

// 3. 注册服务(事件发布者)
@Service
public class UserRegisterService {

    @Autowired
    private ApplicationEventPublisher publisher;

    public void register(String username) {
        System.out.println("用户 " + username + " 注册成功");
        publisher.publishEvent(new UserRegisterEvent(this, username));
    }
}

// 4. REST控制器
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserRegisterService registerService;

    @PostMapping("/register")
    public ResponseEntity<String> register(@RequestParam String username) {
        registerService.register(username);
        return ResponseEntity.ok("用户 " + username + " 注册成功");
    }
}

异步事件支持

为了提升性能,可以通过配置使事件监听异步执行。添加以下配置:

java 复制代码
@Configuration
public class EventConfig {

    @Bean
    public ApplicationEventMulticaster applicationEventMulticaster() {
        SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
        eventMulticaster.setTaskExecutor(Executors.newFixedThreadPool(10));
        return eventMulticaster;
    }
}

运行示例

启动Spring Boot应用后,调用接口:

bash 复制代码
curl -X POST "http://localhost:8080/user/register?username=Alice"

输出

makefile 复制代码
用户 Alice 注册成功
邮件通知: 欢迎用户 Alice 加入我们!
记录日志: 用户 Alice 于 2025-04-24 10:00:00 注册成功
分配积分: 为用户 Alice 添加100欢迎积分

说明

  1. 解耦性UserRegisterService仅负责注册逻辑,邮件、日志、积分等功能由独立的监听器实现。
  2. 扩展性:新增功能(如发送短信通知)只需创建新的监听器,无需修改核心代码。
  3. Spring支持 :Spring自动发现@Component标注的监听器,并通过ApplicationEventPublisher分发事件。
  4. 异步处理 :通过配置TaskExecutor,监听器可以异步执行,适合耗时操作(如发送邮件)。

6. 观察者模式的优缺点

优点

  1. 松耦合:发布者与订阅者完全解耦,互不依赖具体实现。
  2. 动态扩展:支持运行时添加或移除观察者,灵活性高。
  3. 事件驱动:适合异步处理和消息驱动架构,提升系统响应性。
  4. 符合开闭原则:新增观察者无需修改核心逻辑。

缺点

  1. 性能开销:大量观察者可能导致通知时间增加,需考虑异步处理。
  2. 内存泄漏风险:未及时移除的观察者可能导致内存泄漏,需谨慎管理。
  3. 复杂性增加:事件流复杂时,调试和追踪可能变得困难。

7. 总结

观察者模式是构建事件驱动系统的核心模式,通过松耦合的发布-订阅机制,实现了核心逻辑与响应逻辑的解耦。在Spring和Spring Boot中,ApplicationEventApplicationListener提供了强大的事件处理支持,广泛应用于容器管理、业务通知、异步处理等场景。熟练掌握观察者模式及其在Spring中的应用,有助于开发者构建高内聚、低耦合、可扩展的现代应用架构。观察者模式不仅是设计模式,更是事件驱动开发范式的灵魂。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢

相关推荐
.生产的驴17 分钟前
SpringBoot 封装统一API返回格式对象 标准化开发 请求封装 统一格式处理
java·数据库·spring boot·后端·spring·eclipse·maven
时间之城29 分钟前
笔记:记一次使用EasyExcel重写convertToExcelData方法无法读取@ExcelDictFormat注解的问题(已解决)
java·spring boot·笔记·spring·excel
Aniugel2 小时前
JavaScript高级面试题
javascript·设计模式·面试
不当菜虚困2 小时前
JAVA设计模式——(四)门面模式
java·开发语言·设计模式
Niuguangshuo2 小时前
Python设计模式:MVC模式
python·设计模式·mvc
Lei活在当下3 小时前
【现代 Android APP 架构】01. APP 架构综述
android·设计模式·架构
前端大白话3 小时前
震惊!90%前端工程师都踩过的坑!computed属性vs methods到底该怎么选?一文揭秘高效开发密码
前端·vue.js·设计模式
前端大白话3 小时前
前端必看!figure标签在响应式图片排版中的王炸操作,grid/flex布局实战指南
前端·设计模式·html
ApeAssistant3 小时前
Spring + 设计模式 (十三) 行为型 - 策略模式
spring·设计模式