<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們來以應用啟動事件:ApplicationStartingEvent為例來進行說明:
以啟動類的SpringApplication.run方法為入口,跟進SpringApplication的兩個同名方法後,我們會看到主要的run方法,方法比較長,在這裡只貼出與監聽器密切相關的關鍵的部分:
SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting();
我們跟進這個starting方法,方法的內容如下:
void starting() { for (SpringApplicationRunListener listener : this.listeners) { listener.starting(); } }
這裡的listeners已經在getRunListeners方法中完成了載入,載入原理類似於系統初始化器,關於系統初始化器的載入可以參考SpringBoot深入淺出分析初始化器
starting方法邏輯很簡單,就是呼叫SpringApplicationRunListener的starting方法。下面繼續分析這個starting方法:
我們進入了EventPublishingRunListener類(SpringApplicationRunListener 的實現類)的starting方法:
@Override public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); }
這裡就使用了廣播器,來廣播新的ApplicationStartingEvent事件。
我們跟進這個multicastEvent方法:
@Override public void multicastEvent(ApplicationEvent event) { multicastEvent(event, resolveDefaultEventType(event)); }
繼續看同名的方法multicastEvent:
@Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } }
這裡的ResolvableType 是對event做了包裝,我們不去關注;由於我們沒有建立執行緒池,所以executor是空的。我們重點關注兩個部分:
1、getApplicationListeners --> 獲取所有關注此事件的監聽器(※);
2、invokeListener --> 啟用監聽器;
getApplicationListeners (AbstractApplicationEventMulticaster類中)方法,程式碼如下:
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); // Quick check for existing entry on ConcurrentHashMap... ListenerRetriever retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { // Fully synchronized building and caching of a ListenerRetriever synchronized (this.retrievalMutex) { retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } retriever = new ListenerRetriever(true); Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } else { // No ListenerRetriever caching -> no synchronization necessary return retrieveApplicationListeners(eventType, sourceType, null); } }
入參中的event就是ApplicationStartingEvent,sourceType是org.springframework.boot.SpringApplication類。ListenerRetriever型別本人將其視作是一個儲存監聽器的容器。
可以看出,程式首先在快取裡面尋找ListenerRetriever型別的retriever,如果沒有找到,加鎖再從快取裡面找一次。這裡我們快取裡是沒有內容的,所以都不會返回。
接下來呼叫了retrieveApplicationListeners方法,來遍歷所有的監聽器。retrieveApplicationListeners方法比較長,我們重點關注下supportsEvent(listener, eventType, sourceType)方法,該方法用來判斷是否此監聽器關注該事件,過程主要包括,判斷此型別是否是GenericApplicationListener型別,如果不是,則構造一個代理,代理的目的是,通過泛型解析,最終獲得監聽器所感興趣的事件。
如果經過判斷,監聽器對該事件是感興趣的,則此監聽器會被加入監聽器列表中。
protected boolean supportsEvent( ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) { GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener)); return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); }
當某個事件所有的監聽器被收集完畢後,multicastEvent(SimpleApplicationEventMulticaster類)方法會對事件進行傳播。即呼叫監聽器的通用觸發介面方法:listener.onApplicationEvent(event);這樣,就完成了這個事件的傳播。
到此這篇關於SpringBoot深入分析講解監聽器模式下的文章就介紹到這了,更多相關SpringBoot監聽器模式內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45