1. 使用Spring 事件
首先spring事件分为事件发布者(EventPublisher)、事件监听者(EventListener),还包括一个事件广播者(这个是spring实现相关,这一节不讨论)。使用spring事件机制,需要自定义事件发布者和监听者。
以一个简单的例子开始,事件发布者发送一个string类型的消息,接受者将接收到的消息打印出来。
1.1 事件发布者
1 |
|
关于ApplicationEventPublisherAware如下:
1 | public interface ApplicationEventPublisher { |
用户发布的事件类型可以是:
- 用户可以继承ApplicationEvent从而自定义Event类型
- 也可以使用任意Object类型,但是如果event真实类型不是ApplicationEvent的话,那么event会被封装成PayloadApplicationEvent
1.2 事件监听者
1 | //事件监听者需要实现ApplicationListener接口 |
关于发布出去的事件,那些监听者会监听到?
- 发布的事件类型是
ApplicationEvent
的实现类A
那么所有监听者的onApplicationEvent
的参数类型是A或者A的子类都会收到事件。 - 发布的事件类型是不是ApplicationEvent类型,类型是B
这种情况下,最终事件会被包装成PayloadApplicationEvent<B>
, 那么所有监听者方法onApplicationEvent
的参数是PayloadApplicationEvent<B>
的监听者会收到, 假设有C是B的父类,且有一个监听者X监听PayloadApplicationEvent<C>
,那X是收不到PayloadApplicationEvent<B>
类型的事件的
2. Spring事件原理
Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者,工作流程如下:
也就是说上面代码中发布者调用applicationEventPublisher.publishEvent(msg);
是会将事件发送给了EventMultiCaster, 而后由EventMultiCaster注册着所有的Listener,然后根据事件类型决定转发给那个Listener。
2.1 EventMultiCaster
ApplicationContext完成bean的装配和初始化后(非lazy-init的singleton bean会加载后就初始化),会尝试创建一个eventMultiCaster,创建代码如下:
1 | protected void initApplicationEventMulticaster() { |
- 默认SimpleApplicationEventMulticaster
直接看一下SimpleApplicationEventMulticaster用来广播event的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
// 这个是用来根据event的类型找到合适的listener的
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
// executor不是空的时候会在executor中激活listener
if (executor != null) {
executor.execute(new Runnable() {
public void run() {
invokeListener(listener, event);
}
});
}
// 否则就直接在当前调用线程中激活listener
else {
invokeListener(listener, event);
}
}
}
在创建SimpleApplicationEventMulticaster时,executor是null,所以默认情况下所有的listener 的onApplicationEvent是直接在当前线程(事件发布者所在线程)中调用,所以
如果onApplicationEvent有阻塞操作也会导致事件发布者被阻塞,后续的其他listener也会被阻塞无法调用。
- 自定义multicaster
「2.1」中介绍spring会加载一个叫applicationEventMulticaster且实现了ApplicationEventMulticaster接口的multicaster,自定义multicaster需要实现了该接口然后将bean的名字设为applicationEventMulticaster即可。
下面的例子为默认的SimpleApplicationEventMulticaster添加了executor,以使事件发布者和监听者不用在同一个线程中调用:
1 | //使用线程池运行listener |
3. 附
Spring启动完成之后(已经完成bean解析,non-lazy-init的singleton实例化和初始化,完成listener的注册),默认会发布一个ContextRefreshedEvent事件,该事件包装的消息是一个ApplicationContext对象。