--- title: Spring 事件 date: 2022-12-22 20:31:02 order: 25 categories: - Java - 框架 - Spring - Spring核心 tags: - Java - 框架 - Spring permalink: /pages/41814824/ --- # Spring 事件 ## Java 事件/监听器编程模型 设计模式 - 观察者模式扩展 - 可观者对象(消息发送者) - java.util.Observable - 观察者 - java.util.Observer 标准化接口 - 事件对象 - java.util.EventObject - 事件监听器 - java.util.EventListener ## 面向接口的事件/监听器设计模式 事件/监听器场景举例 | Java 技术规范 | 事件接口 | 监听器接口 | | --------------- | ------------------------------------- | ---------------------------------------- | | JavaBeans | java.beans.PropertyChangeEvent | java.beans.PropertyChangeListener | | Java AWT | java.awt.event.MouseEvent | java.awt.event.MouseListener | | Java Swing | javax.swing.event.MenuEvent | javax.swing.event.MenuListener | | Java Preference | java.util.prefs.PreferenceChangeEvent | java.util.prefs.PreferenceChangeListener | ## 面向注解的事件/监听器设计模式 事件/监听器注解场景举例 | Java 技术规范 | 事件注解 | 监听器注解 | | ------------- | ------------------------------ | ------------------------------------- | | Servlet 3.0+ | | @javax.servlet.annotation.WebListener | | JPA 1.0+ | @javax.persistence.PostPersist | | | Java Common | @PostConstruct | | | EJB 3.0+ | @javax.ejb.PrePassivate | | | JSF 2.0+ | @javax.faces.event.ListenerFor | | ## Spring 标准事件 - ApplicationEvent Java 标准事件 `java.util.EventObject` 扩展 - 扩展特性:事件发生事件戳 - Spring 应用上下文 ApplicationEvent 扩展 - `ApplicationContextEvent` - Spring 应用上下文(ApplicationContext)作为事件源 具体实现: - `org.springframework.context.event.ContextClosedEvent` - `org.springframework.context.event.ContextRefreshedEvent` - `org.springframework.context.event.ContextStartedEvent` - `org.springframework.context.event.ContextStoppedEvent` ## 基于接口的 Spring 事件监听器 Java 标准事件监听器 `java.util.EventListener` 扩展 - 扩展接口 - `org.springframework.context.ApplicationListener` - 设计特点:单一类型事件处理 - 处理方法:`onApplicationEvent(ApplicationEvent)` - 事件类型:`org.springframework.context.ApplicationEvent` ## 基于注解的 Spring 事件监听器 Spring 注解 - `@org.springframework.context.event.EventListener` | 特性 | 说明 | | -------------------- | -------------------------------------------- | | 设计特点 | 支持多 `ApplicationEvent` 类型,无需接口约束 | | 注解目标 | 方法 | | 是否支持异步执行 | 支持 | | 是否支持泛型类型事件 | 支持 | | 是指支持顺序控制 | 支持,配合 `@Order` 注解控制 | ## 注册 Spring ApplicationListener - 方法一:ApplicationListener 作为 Spring Bean 注册 - 方法二:通过 ConfigurableApplicationContext API 注册 ## Spring 事件发布器 - 方法一:通过 ApplicationEventPublisher 发布 Spring 事件 - 获取 ApplicationEventPublisher - 依赖注入 - 方法二:通过 ApplicationEventMulticaster 发布 Spring 事件 - 获取 ApplicationEventMulticaster - 依赖注入 - 依赖查找 ## Spring 层次性上下文事件传播 - 发生说明 - 当 Spring 应用出现多层次 Spring 应用上下文(ApplicationContext)时,如 Spring WebMVC、Spring Boot 或 Spring Cloud 场景下,由子 ApplicationContext 发起 Spring 事件可能会传递到其 Parent ApplicationContext(直到 Root)的过程 - 如何避免 - 定位 Spring 事件源(ApplicationContext)进行过滤处理 ## Spring 内建事件 ApplicationContextEvent 派生事件 - ContextRefreshedEvent :Spring 应用上下文就绪事件 - ContextStartedEvent :Spring 应用上下文启动事件 - ContextStoppedEvent :Spring 应用上下文停止事件 - ContextClosedEvent :Spring 应用上下文关闭事件 ## Spring 4.2 Payload 事件 Spring Payload 事件 - org.springframework.context.PayloadApplicationEvent - 使用场景:简化 Spring 事件发送,关注事件源主体 - 发送方法:ApplicationEventPublisher#publishEvent(java.lang.Object) ## 自定义 Spring 事件 - 扩展 org.springframework.context.ApplicationEvent - 实现 org.springframework.context.ApplicationListener - 注册 org.springframework.context.ApplicationListener ## 依赖注入 ApplicationEventPublisher - 通过 ApplicationEventPublisherAware 回调接口 - 通过 @Autowired ApplicationEventPublisher ## 依赖查找 ApplicationEventMulticaster 查找条件 - Bean 名称:"applicationEventMulticaster" - Bean 类型:org.springframework.context.event.ApplicationEventMulticaster ## ApplicationEventPublisher 底层实现 - 接口:org.springframework.context.event.ApplicationEventMulticaster - 抽象类:org.springframework.context.event.AbstractApplicationEventMulticaster - 实现类:org.springframework.context.event.SimpleApplicationEventMulticaster ## 同步和异步 Spring 事件广播 基于实现类 - `org.springframework.context.event.SimpleApplicationEventMulticaster` - 模式切换:`setTaskExecutor(java.util.concurrent.Executor)` 方法 - 默认模式:同步 - 异步模式:如 `java.util.concurrent.ThreadPoolExecutor` - 设计缺陷:非基于接口契约编程 基于注解 - `@org.springframework.context.event.EventListener` - 模式切换 - 默认模式:同步 - 异步模式:标注 `@org.springframework.scheduling.annotation.Async` - 实现限制:无法直接实现同步/异步动态切换 ## Spring 4.1 事件异常处理 Spring 3.0 错误处理接口 - org.springframework.util.ErrorHandler 使用场景 - Spring 事件(Events) - SimpleApplicationEventMulticaster Spring 4.1 开始支持 - Spring 本地调度(Scheduling) - org.springframework.scheduling.concurrent.ConcurrentTaskScheduler - org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler ## Spring 事件/监听器实现原理 核心类 - `org.springframework.context.event.SimpleApplicationEventMulticaster` - 设计模式:观察者模式扩展 - 被观察者 - org.springframework.context.ApplicationListener - API 添加 - 依赖查找 - 通知对象 - org.springframework.context.ApplicationEvent - 执行模式:同步/异步 - 异常处理:org.springframework.util.ErrorHandler - 泛型处理:org.springframework.core.ResolvableType ## 问题 **Spring Boot 事件** | 事件类型 | 发生时机 | | ----------------------------------- | --------------------------------------- | | ApplicationStartingEvent | 当 Spring Boot 应用已启动时 | | ApplicationStartedEvent | 当 Spring Boot 应用已启动时 | | ApplicationEnvironmentPreparedEvent | 当 Spring Boot Environment 实例已准备时 | | ApplicationPreparedEvent | 当 Spring Boot 应用预备时 | | ApplicationReadyEvent | 当 Spring Boot 应用完全可用时 | | ApplicationFailedEvent | 当 Spring Boot 应用启动失败时 | **Spring Cloud 事件** | 事件类型 | 发生时机 | | -------------------------- | ------------------------------------- | | EnvironmentChangeEvent | 当 Environment 示例配置属性发生变化时 | | HeartbeatEvent | 当 DiscoveryClient 客户端发送心跳时 | | InstancePreRegisteredEvent | 当服务实例注册前 | | InstanceRegisteredEvent | 当服务实例注册后 | | RefreshEvent | 当 RefreshEndpoint 被调用时 | | RefreshScopeRefreshedEvent | 当 Refresh Scope Bean 刷新后 | **Spring 事件核心接口/组件**? - Spring 事件 - org.springframework.context.ApplicationEvent - Spring 事件监听器 - org.springframework.context.ApplicationListener - Spring 事件发布器 - org.springframework.context.ApplicationEventPublisher - Spring 事件广播器 - org.springframework.context.event.ApplicationEventMulticaster **Spring 同步和异步事件处理的使用场景**? - Spring 同步事件 - 绝大多数 Spring 使用场景,如 ContextRefreshedEvent - Spring 异步事件 - 主要 @EventListener 与 @Async 配合,实现异步处理,不阻塞主线程,比如长时间的数据计算任务等。不要轻易调整 SimpleApplicationEventMulticaster 中关联的 taskExecutor 对象,除非使用者非常了解 Spring 事件机制,否则容易出现异常行为。 ## 参考资料 - [Spring 官方文档之 Core Technologies](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans) - [《小马哥讲 Spring 核心编程思想》](https://time.geekbang.org/course/intro/265)