Spring 事件机制

为什么要有事件机制?

在一个系统中,不同模块经常需要“感知”某些行为发生,比如:

  • 用户注册成功后,发送欢迎邮件
  • 订单创建后,通知库存服务
  • Spring 容器刷新完毕后,执行一些初始化逻辑
    我们不希望模块之间直接耦合调用。
    Spring 提供了内置的 事件发布/监听模型 来优雅解决这个问题。

事件模型的三要素

组件 作用 常见实现类
事件(ApplicationEvent) 封装消息数据 自定义事件类
事件发布器(ApplicationEventPublisher) 负责发布事件 ApplicationContext 本身
事件监听器(ApplicationListener) 监听并处理事件 自定义监听类

核心类结构

flowchart TD
    A[ApplicationEventPublisher] -->|publishEvent| B[ApplicationEventMulticaster]
    B -->|for each listener| C[ApplicationListener]
    C -->|onApplicationEvent| D[处理业务逻辑]

ApplicationContext 既是 Bean 工厂,也是事件发布器,它内部维护了一个事件广播器(ApplicationEventMulticaster)。

自定义事件 Demo

1️⃣ 定义事件

1
2
3
4
5
6
7
8
9
10
11
12
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️⃣ 定义监听器

1
2
3
4
5
6
7
8
9
@Service
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisterEvent> {
@Override
public void onApplicationEvent(UserRegisterEvent event) {
System.out.println("发送欢迎邮件给用户:" + event.getUsername());
}
}

3️⃣ 发布事件

1
2
3
4
5
6
7
8
9
10
11
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher publisher;

public void registerUser(String username) {
System.out.println("用户注册成功:" + username);
// 发布事件
publisher.publishEvent(new UserRegisterEvent(this, username));
}
}

4️⃣ 测试运行

1
2
3
4
5
6
7
8
9
10
@SpringBootTest
class EventTest {
@Autowired
private UserService userService;

@Test
void testRegister() {
userService.registerUser("ryan");
}
}

运行结果:

1
2
用户注册成功:ryan
发送欢迎邮件给用户:ryan

Spring 事件源码流程

当你调用:

1
publisher.publishEvent(event);

实际调用的是:

1
AbstractApplicationContext#publishEvent()

源码简化:

1
2
3
public void publishEvent(ApplicationEvent event) {
getApplicationEventMulticaster().multicastEvent(event);
}

然后:

1
SimpleApplicationEventMulticaster#multicastEvent()
1
2
3
for (ApplicationListener<?> listener : getApplicationListeners(event)) {
listener.onApplicationEvent(event);
}

📌 核心逻辑:

  • 拿到所有监听当前事件的监听器
  • 挨个执行 onApplicationEvent()
    如果容器里配置了异步执行器(Executor),还可以异步广播事件。

同步 vs 异步事件

默认情况下事件是同步广播的:

  • 发布者会等待所有监听器处理完事件后才继续执行
    如果想让监听器异步执行:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @EnableAsync
    @Component
    public class WelcomeEmailListener implements ApplicationListener<UserRegisterEvent> {
    @Async
    @Override
    public void onApplicationEvent(UserRegisterEvent event) {
    System.out.println("异步发送邮件:" + event.getUsername());
    }
    }

调试建议

  1. AbstractApplicationContext#publishEvent() 打断点
  2. 进入 SimpleApplicationEventMulticaster#multicastEvent()
  3. 查看容器里有哪些监听器被选中执行
  4. 如果想看容器内置事件,可在容器启动时观察:
    • ContextRefreshedEvent
    • ContextClosedEvent