Spring源码 第九篇:Spring 5 源码深度拆解 - Spring 事件驱动模型

👋 前言

前面我们已经详细探讨了:IOC、生命周期、循环依赖、AOP、事务、SpringMVC、Boot 自动配置、资源加载与 Environment。

Spring 内部也存在靠事件驱动解耦的机制:容器启动、刷新、容器刷新(refresh)完成后发布 ContextRefreshedEvent,此时所有 Bean 均已初始化完毕,是最常用的启动后逻辑入口......这一篇我们梳理事件模型,了解掌握 Spring 轻量但极其重要的扩展机制。

即刻起,简单又轻松。


一、核心角色

  • ApplicationEvent:事件本身(所有事件的父类)
  • ApplicationListener:事件监听器(观察者)
  • ApplicationEventPublisher:事件发布器(被观察者)
  • ApplicationContext:本身就是发布器,内部维护监听器
  • ApplicationEventMulticaster :Spring 通过 AbstractApplicationContext.initApplicationEventMulticaster() 方法初始化事件多播器。默认创建的是 SimpleApplicationEventMulticaster 实例;同时还承担了事件匹配和路由的重要职责------它需要根据事件类型找到对应的监听器进行派发

二、最简流程

  1. 定义事件
    • extends ApplicationEvent(经典方式)
    • 直接使用任意 POJO
  2. 定义监听器 implements ApplicationListener
  3. 容器启动时收集所有监听器
  4. 调用 publishEvent 发布
  5. Spring 遍历匹配监听器执行 onApplicationEvent

三、Spring 内置核心事件

事件类型 触发时机
ContextRefreshedEvent 容器完全刷新完成(Bean 都初始化好了)
ContextStartedEvent 容器启动
ContextStoppedEvent 容器停止
ContextClosedEvent 容器关闭(单例 Bean 销毁前)
RequestHandledEvent SpringMVC 请求处理完成

最常用ContextRefreshedEvent,很多框架启动逻辑都监听它。


四、源码级流程:事件是怎么被发布和消费的?

核心调用链

java 复制代码
// 1. 发布入口
publishEvent(Object event) 
    ↓
// 2. 获取事件类型,包装为 ApplicationEvent(若 event 本身不是)
getApplicationEventMulticaster() 
    ↓
// 3. 多播器开始派发
multicastEvent(ApplicationEvent event, ResolvableType eventType)
    ↓
// 4. 获取所有匹配的监听器
getApplicationListeners(event, type)
    ↓
// 5. 遍历监听器,逐个调用
invokeListener(listener, event)
    ↓
// 6. 最终执行监听器的回调
listener.onApplicationEvent(event)

1. 发布入口:publishEvent

几乎所有地方最终都会走到:

java 复制代码
// AbstractApplicationContext
protected void publishEvent(Object event, @Nullable ResolvableType typeHint) {
    // 1. 包装成 ApplicationEvent
    ApplicationEvent applicationEvent = null;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    } else {
        applicationEvent = new PayloadApplicationEvent<>(this, event);
    }

    // 2. 获取多播器
    ApplicationEventMulticaster multicaster = this.applicationEventMulticaster;

    // 3. 多播事件:发给所有匹配监听器
    multicaster.multicastEvent(applicationEvent, typeHint);
}

2. 事件多播核心:SimpleApplicationEventMulticaster

java 复制代码
@Override
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType typeHint) {
    ResolvableType eventType = (typeHint != null ? typeHint : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();

    for (ApplicationListener<?> listener : getApplicationListeners(event, eventType)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        } else {
            invokeListener(listener, event);
        }
    }
}

3. 最终执行监听器

java 复制代码
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    listener.onApplicationEvent(event);
}

五、@EventListener 注解原理

1. 解析器:EventListenerMethodProcessor

EventListenerMethodProcessor 实现 SmartInitializingSingleton 接口,在容器所有单例 Bean 完成实例化、依赖注入、初始化之后,执行 afterSingletonsInstantiated()

SmartInitializingSingleton.afterSingletonsInstantiated() 的触发时机是"所有单例 Bean 实例化完成之后的一次性回调;而实例化、依赖注入、初始化是 bean 生命周期中更早阶段发生的事情。

2. 核心流程

  1. 遍历所有单例 Bean
  2. 找出带 @EventListener 的方法
  3. 解析监听的事件类型
  4. 包装成 ApplicationListenerMethodAdapter
  5. 注册到 ApplicationEventMulticaster

3. 执行时

发布事件 → 匹配 adapter → 反射调用你写的 @EventListener 方法。


六、异步事件 @Async + 事件

Spring 事件默认是同步执行的(发布者线程阻塞直到所有监听器执行完毕)。

开启步骤

全局异步(所有事件都异步)

重写 applicationEventMulticaster Bean,为其设置 TaskExecutor

配置后,所有事件的派发都会提交到线程池中执行,发布者线程立即返回。

java 复制代码
@Configuration
public class AsyncEventConfig {

    @Bean(name = "applicationEventMulticaster")
    public ApplicationEventMulticaster applicationEventMulticaster() {
        SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
        multicaster.setTaskExecutor(Executors.newFixedThreadPool(5));  // 设置线程池
        return multicaster;
    }
}
局部异步
  1. 启动类加 @EnableAsync

    java 复制代码
    @EnableAsync   // 启动类或配置类上添加
    @SpringBootApplication
    public class Application { ... }
  2. 监听方法上加 @Async

    java 复制代码
    @Component
    public class OrderEventListener {
    
        @Async   // 仅此监听器异步执行
        @EventListener
        public void handleOrder(OrderEvent event) {
            // 异步处理逻辑
        }
    }
  3. 配置 TaskExecutor Bean(可选但强烈建议配置)

可自定义 TaskExecutor Bean 控制线程池,不配置则使用默认的 SimpleAsyncTaskExecutor(每个任务新建线程,不推荐生产环境使用)。

原理

多播时判断有 executor 就提交线程池,不阻塞主线程。


七、事务绑定事件 @TransactionalEventListener

核心TransactionSynchronization

若发布事件时不存在事务,默认直接执行,可通过 fallbackExecution 控制。

原理

  1. 不立即执行监听方法
  2. 把执行逻辑挂到事务同步管理器
  3. 等事务 提交 / 回滚 / 完成 后再执行

常用阶段

  • BEFORE_COMMIT
  • AFTER_COMMIT
  • AFTER_ROLLBACK
  • AFTER_COMPLETION

这是微服务 / 分布式事务里非常实用的 "事务完成后再发消息" 方案。


八、Spring 事件完整总结

组件 说明
事件 ApplicationEvent
监听 ApplicationListener / @EventListener
发布 ApplicationContext.publishEvent
调度 ApplicationEventMulticaster
异步 @Async + TaskExecutor
事务绑定 @TransactionalEventListener
内置事件 启动 / 刷新 / 停止 / 关闭

轻量、解耦、无侵入,是 Spring 内部和业务扩展最常用的机制之一。

相关推荐
ForgeAI码匠2 小时前
ForgeAdmin|Spring Boot 3 后台框架的自动配置设计:少写配置,多做组合
java·spring boot·后端
tongluowan0072 小时前
Redisson的参数及工作原理
java·redis·lua·分布式锁
IT_陈寒2 小时前
为什么 Java 的 Optional 让我调试到深夜?
前端·人工智能·后端
仙俊红3 小时前
Integer\int对比,equals()\hashcode面试
java·面试·职场和发展
用户8356290780513 小时前
用 Python 实现 Excel 散点图绘制与定制
后端·python
WiChP3 小时前
【V0.1B10】从零开始的2D游戏引擎开发之路
java·数据库·游戏引擎
怪兽陪你看日出B3 小时前
一文彻底搞懂本地缓存之王-Caffeine
后端
JavaGuide3 小时前
Spec Coding 规范驱动编程实战:从 Vibe Coding 到 AI 代码规范
后端·vibecoding
云烟成雨TD3 小时前
Spring AI Alibaba 1.x 系列【60】检查点机制原理与全流程剖析
java·人工智能·spring