1. 使用Spring 事件
首先spring事件分為事件發(fā)布者(EventPublisher)、事件監(jiān)聽者(EventListener),還包括一個(gè)事件廣播者(這個(gè)是spring實(shí)現(xiàn)相關(guān),這一節(jié)不討論)。使用spring事件機(jī)制,需要自定義事件發(fā)布者和監(jiān)聽者。
以一個(gè)簡單的例子開始,事件發(fā)布者發(fā)送一個(gè)string類型的消息,接受者將接收到的消息打印出來。
- 事件發(fā)布者
@Component
public class SaySomethingPublisher implements ApplicationEventPublisherAware{
private ApplicationEventPublisher applicationEventPublisher;
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void saySomething(String msg){
applicationEventPublisher.publishEvent(msg);
}
}
需要實(shí)現(xiàn)ApplicationEventPublisherAware這個(gè)Aware接口,廣播事件需要利用applicationEventPublisher
關(guān)于ApplicationEventPublisherAware如下:
public interface ApplicationEventPublisher {
void publishEvent(ApplicationEvent event);
void publishEvent(Object event);
}
用戶發(fā)布的事件類型可以是:
1. 用戶可以繼承ApplicationEvent從而自定義Event類型
2. 也可以使用任意Object類型,但是如果event真實(shí)類型不是ApplicationEvent的話,那么event會(huì)被封裝成PayloadApplicationEvent
- 事件監(jiān)聽者
//事件監(jiān)聽者需要實(shí)現(xiàn)ApplicationListener接口
@Component
public class ListenerA implements ApplicationListener<PayloadApplicationEvent<String>> {
// 由于監(jiān)聽的是String類型的事件會(huì)被封裝成PayloadApplicationEvent,所以此處類型是PayloadApplicationEvent
public void onApplicationEvent(PayloadApplicationEvent event) {
// getSource返回真實(shí)的事件
Object msg = event.getSource();
System.out.println("ListenerA receive:" + msg);
}
}
關(guān)于發(fā)布出去的事件,那些監(jiān)聽者會(huì)監(jiān)聽到?
- 發(fā)布的事件類型是ApplicationEvent的實(shí)現(xiàn)類A
那么所有監(jiān)聽者的onApplicationEvent
的參數(shù)類型是A或者A的子類都會(huì)收到事件。 - 發(fā)布的事件類型是不是ApplicationEvent類型,類型是B
這種情況下,最終事件會(huì)被包裝成PayloadApplicationEvent<B>
, 那么所有監(jiān)聽者方法onApplicationEvent
的參數(shù)是PayloadApplicationEvent<B>
的監(jiān)聽者會(huì)收到, 假設(shè)有C是B的父類,且有一個(gè)監(jiān)聽者X監(jiān)聽PayloadApplicationEvent<C>
,那X是收不到PayloadApplicationEvent<B>
類型的事件的
2. Spring事件原理
Spring事件機(jī)制是觀察者模式的一種實(shí)現(xiàn),但是除了發(fā)布者和監(jiān)聽者者兩個(gè)角色之外,還有一個(gè)EventMultiCaster的角色負(fù)責(zé)把事件轉(zhuǎn)發(fā)給監(jiān)聽者,工作流程如下:
也就是說上面代碼中發(fā)布者調(diào)用applicationEventPublisher.publishEvent(msg);
是會(huì)將事件發(fā)送給了EventMultiCaster, 而后由EventMultiCaster注冊著所有的Listener,然后根據(jù)事件類型決定轉(zhuǎn)發(fā)給那個(gè)Listener。
2.1 EventMultiCaster
ApplicationContext完成bean的裝配和初始化后(非lazy-init的singleton bean會(huì)加載后就初始化),會(huì)嘗試創(chuàng)建一個(gè)eventMultiCaster,創(chuàng)建代碼如下:
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判斷有沒有一個(gè)name是“applicationEventMulticaster”且實(shí)現(xiàn)了“ ApplicationEventMulticaster”的bean,有的話那它就是eventMultiCaster
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 沒有這樣一個(gè)bean,那就會(huì)創(chuàng)建一個(gè)默認(rèn)的
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
- 默認(rèn)SimpleApplicationEventMulticaster
直接看一下SimpleApplicationEventMulticaster用來廣播event的代碼:
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
// 這個(gè)是用來根據(jù)event的類型找到合適的listener的
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
// executor不是空的時(shí)候會(huì)在executor中激活listener
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
// 否則就直接在當(dāng)前調(diào)用線程中激活listener
else {
invokeListener(listener, event);
}
}
}
在創(chuàng)建SimpleApplicationEventMulticaster時(shí),executor是null,所以默認(rèn)情況下所有的listener 的onApplicationEvent
是直接在當(dāng)前線程(事件發(fā)布者所在線程)中調(diào)用,所以
如果onApplicationEvent有阻塞操作也會(huì)導(dǎo)致事件發(fā)布者被阻塞,后續(xù)的其他listener也會(huì)被阻塞無法調(diào)用。
- 自定義multicaster
「2.1」中介紹spring會(huì)加載一個(gè)叫applicationEventMulticaster
且實(shí)現(xiàn)了ApplicationEventMulticaster
接口的multicaster,自定義multicaster需要實(shí)現(xiàn)了該接口然后將bean的名字設(shè)為applicationEventMulticaster
即可。
下面的例子為默認(rèn)的SimpleApplicationEventMulticaster
添加了executor,以使事件發(fā)布者和監(jiān)聽者不用在同一個(gè)線程中調(diào)用:
//使用線程池運(yùn)行l(wèi)istener
<bean id="executorService" class="java.util.concurrent.Executors" factory-method="newCachedThreadPool">
</bean>
<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<property name="taskExecutor" ref="executorService">
</property>
</bean>
3. 附
- Spring啟動(dòng)完成之后(已經(jīng)完成bean解析,non-lazy-init的singleton實(shí)例化和初始化,完成listener的注冊),默認(rèn)會(huì)發(fā)布一個(gè)
ContextRefreshedEvent
事件,該事件包裝的消息是一個(gè)ApplicationContext對象。