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 内部和业务扩展最常用的机制之一。

相关推荐
阿祖zu18 分钟前
别再优化 RAG 了,适配 Agent 的 LLM Wiki 知识库理念
前端·后端·aigc
昵称为空C1 小时前
手撸一个动态 SQL 执行引擎:不重启服务,在线增删改查任意数据库
spring boot·后端
用户8356290780511 小时前
用 Python 自动化 PowerPoint 演讲者备注添加
后端·python
神奇小汤圆1 小时前
科研神器再升级!Claude Code 全套 Skills,16 大科研场景全覆盖!
后端
东坡白菜1 小时前
破局全栈:一个前端开发的Java入门实战记录(1)
java·全栈
tyung1 小时前
Go 手写有界 SPSC 环形队列:无 CAS、无锁、Cache 友好的无锁模型
后端·go
咕白m6251 小时前
使用 C# 在 Excel 中应用多种字体样式
后端·c#
唐青枫1 小时前
Java Tomcat 实战指南:从 Servlet 容器到 Spring Boot 部署
java
Java编程爱好者1 小时前
放弃 Spring AI?这 3 个开源框架,才是让 SpringBoot 玩转 AI Agent 的正解
后端
二月龙2 小时前
伪类与伪元素深度解析:before/after 实用案例
后端