17、Spring事件.md 11 KB

第十七章: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

  • org.springframework.context.ApplicationEvent

  • Java 标准事件java.util.EventObject

扩展

  • 扩展特性:事件发生时间戳

  • Spring 应用上下文ApplicationEvent

扩展 -ApplicationContextEvent

  • org.springframework.context.event.ApplicationContextEvent
  • Spring 应用上下文(ApplicationContext)作为事件源
  • 具体实现:
    • org.springframework.context.event.ContextClosedEvent
    • org.springframework.context.event.ContextRefreshedEvent
    • org.springframework.context.event.ContextStartedEvent
    • org.springframework.context.event.ContextStoppedEvent

img

基于接口的 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

  • 基于 Spring 接口:向 Spring 应用上下文注册事件
    • ApplicationListener 作为 Spring Bean 注册
    • 通过 ConfigurableApplicationContext#addApplicationListener API 注册
  • 基于 Spring 注解:@org.springframework.context.event.EventListener

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 事件

  1. 扩展 org.springframework.context.ApplicationEvent
  2. 实现 org.springframework.context.ApplicationListener
  3. org.springframework.context.ApplicationListener 注册到容器内

依赖注入 ApplicationEventPublisher

  • 通过 ApplicationEventPublisherAware 回调接口
  • 通过 @Autowired ApplicationEventPublisher

依赖查找 ApplicationEventMulticaster

  • 查找条件
    • Bean 名称:applicationEventMulticaster
    • Bean 类型:org.springframework.context.event.ApplicationEventMulticaster
AbstractApplicationContext#earlyApplicationEvents 在 prepareRefresh() 中从 null 被赋值,在 registerListeners() 的最后,重新被赋值为 null,并进行了早期事件的发布,
因为可能存在一个 Bean 同时实现 BeanPostProcessor 和 ApplicationEventPublisherAware,并在 ApplicationEventPublisherAware#setApplicationEventPublisher 方法中发送事件
因为实现了 BeanPostProcessor,所以这个 Bean 在 registerBeanPostProcessors(beanFactory); 这个方法中初始化,而此时 initApplicationEventMulticaster(); 还没有执行,所以 AbstractApplicationContext#applicationEventMulticaster 为空,无法发布事件,所以先将事件保存在 AbstractApplicationContext#earlyApplicationEvents 中

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
    • 实现限制:无法直接实现同步/异步动态切换

区别:

  • 使用 SimpleApplicationEventMulticaster#setTaskExecutor 的影响是全局的,使用 @Async 是局部的
  • 使用 SimpleApplicationEventMulticaster#setTaskExecutor 需要手动关闭线程池,使用 @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 事件机制,否则容易出现异常行为。