亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

前言

前一段時(shí)間,剛剛接手一個(gè)項(xiàng)目,項(xiàng)目中看到使用的spring的事件監(jiān)聽機(jī)制,加上之前自己看spring源碼的時(shí)候也對(duì)spring listener 有點(diǎn)影像,于是就重新追一追源碼,理一理spring 事件監(jiān)聽機(jī)制的工作原理

案例

  1. 自定義event
spring監(jiān)聽機(jī)制

 

  1. 自定義listener
spring監(jiān)聽機(jī)制

 

  1. 測(cè)試推送
spring監(jiān)聽機(jī)制

 

  1. 測(cè)試結(jié)果
spring監(jiān)聽機(jī)制

 

一個(gè)非常簡單的案例,通過定義事件,監(jiān)聽,推送實(shí)現(xiàn)了簡單的事件監(jiān)聽的流程。

原理分析

  1. 推送事件

通過案例可以看到我們通過
ApplicationContext.publishEvent方法來推送事件,實(shí)際是其子類 AbstractApplicationContext 實(shí)現(xiàn)的發(fā)送操作

spring監(jiān)聽機(jī)制

 

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}

通過源碼可以看到發(fā)送事件最終是交個(gè)
ApplicationEventMulticaster來推送。

那么
ApplicationEventMulticaster對(duì)象是怎么來的呢,它里面具體是如何推送的呢?我們接著往下看。

讀過spring源碼的同學(xué)一定對(duì)
AbstractApplicationContext中的refresh方法很熟悉。這是spring源碼的核心部分,而在其中有一步

spring監(jiān)聽機(jī)制

 

就是來構(gòu)造
ApplicationEventMulticaster。

spring監(jiān)聽機(jī)制

 

參照源碼,我們并沒有定義和注冊(cè)
applicationEventMulticaster,所以就會(huì)使用SimpleApplicationEventMulticaster。

spring監(jiān)聽機(jī)制

 

在multicastEvent中

1,首先是ResolvableType的確認(rèn)

spring監(jiān)聽機(jī)制

 


spring監(jiān)聽機(jī)制

 

可以看到最后是通過Event的class對(duì)象作為ResolvableType的屬性,后面匹配Listener的時(shí)候就是使用這個(gè)。

2,通過ResolvableType獲取適合的Listener

protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Potential new retriever to populate
CachedListenerRetriever newRetriever = null;
// Quick check for existing entry on ConcurrentHashMap
CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
if (existingRetriever == null) {
// Caching a new ListenerRetriever if possible
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
newRetriever = new CachedListenerRetriever();
existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
if (existingRetriever != null) {
newRetriever = null; // no need to populate it in retrieveApplicationListeners
}
}
}
if (existingRetriever != null) {
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
if (result != null) {
return result;
}
// If result is null, the existing retriever is not fully populated yet by another thread.
// Proceed like caching wasn't possible for this current local attempt.
}
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}

這邊這種使用緩存機(jī)制的代碼,可以在spring源碼中多次看到,所以大家可以學(xué)習(xí)這種方式,提高性能。


retrieveApplicationListeners方法比較大,我這邊只截取了部分,可以看到是通過eventType

和sourceType來獲取適合的listener。

spring監(jiān)聽機(jī)制

 

3,接下來就是調(diào)用invokeListener方法來實(shí)際操作,這邊可以看到可以通過Executor

來實(shí)現(xiàn)異步操作。當(dāng)然比較好的方式還是自己配置線程池,這樣可以通過前綴區(qū)分出業(yè)務(wù)。

spring監(jiān)聽機(jī)制

 


spring監(jiān)聽機(jī)制

 

至此可以看到,調(diào)用的是對(duì)應(yīng)listener的onApplicationEvent。

分享到:
標(biāo)簽:spring
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績?cè)u(píng)定