看Spring源碼不得不會的@Enable模塊驅動實現原理講解
- 2022 年 5 月 28 日
- 筆記
這篇文章我想和你聊一聊 spring的@Enable模塊驅動的實現原理。
在我們平時使用spring的過程中,如果想要加個定時任務的功能,那麼就需要加註解@EnableScheduling,如果想使用異步的功能,那就要加@EnableScheduling註解,其實這類註解就是屬於@Enable模塊。
那麼@Enable模塊到底有什麼功能?
模塊是指具備相同領域的功能組件集合,組合所形成一個獨立的單元。比如Web MVC模塊、AspectJ代理模塊Caching緩存模塊,JMX(Java管理擴展)、Async異步處理模塊等。所謂模塊裝配,簡而言之就是,通過@EnableXXX註解實現一個開關,這個開關決定是否開啟某個功能模塊的所有組件的自動化配置。
那麼@EnableXXX註解是如何生效的?
其實@EnableXXX只是一個名字,通過這個名字讓人知道實現了什麼功能,其實這個註解叫什麼名字其實是無所謂的,就算不叫@EnableXXX都行,只不過spring內部都叫@EnableXXX,我們就習慣叫@Enable模塊,所以核心不是這個註解,而是註解實現的套路。
接下來我們來說說這個註解功能實現的套路
一般@EnableXXX註解是通過@Import實現具體的功能(@EnableXXX註解上加個@Import註解),@Import才是@EnableXXX起效果的核心功能。@Import大家都知道,就是往容器裏面注入一個配置類,但是這個配置類可是有講究的。
這裡我直接上源碼,帶你看看@Import註解功能是如何實現的。
@Import註解的功能是在org.springframework.context.annotation.ConfigurationClassParser類processImports方法處理的。接下來我們就來解讀一下實現的核心部分。
首先判斷@Import註解導入的是配置類有沒有實現ImportSelector接口,實現的話就就調用ImportSelector的selectImports方法,這個方法返回的是一批配置類的全限定名,然後繼續解析這些配置類。
ImportSelector接口的作用其實就是往spring容器中再次注入一批配置類。
如果沒有實現ImportSelector接口,那麼再判斷有沒有實現ImportBeanDefinitionRegistrar,有的話就會調用ImportBeanDefinitionRegistrar的registerBeanDefinitions方法,通過名字也可以判斷出,其實就是往spring容器注入一些BeanDefinition。
ImportBeanDefinitionRegistrar的作用其實很簡單,就是往spring容器注入一些BeanDefinition。如果不是很清楚BeanDefinition是什麼,歡迎查看Spring bean到底是如何創建的?(上)這篇文章,有講解。
如果這兩個接口都沒有實現,那麼就當時一個普通的配置類進行解析。
讀完@Import實現的源碼,我們再來總結回顧@Import的作用。
@Import註解,就是導入一個配置類,但是這個配置類分為不同的情況。如果這個配置類實現了ImportSelector接口,那麼就會調用selectImports方法的實現,獲取一批配置類的全限定名,然後再解析配置類;如果實現了@Import註解導入的配置類實現類ImportBeanDefinitionRegistrar,那麼就會調用registerBeanDefinitions方法的實現,這個方法可以往容器中注入BeanDefinition;最後如果都沒實現,那麼就按照一個普通的配置類來解析。
所以基於這麼一套配置類解析的規則,就可以實現往容器中注入一些bean,通過這些bean來完成某塊功能的實現。
@EnbaleAsync註解的是如何起作用的
懂了@Enbale模塊驅動的基本原理,接下來我們舉個例子,來看看@EnbaleAsync註解是如何實現的。
@EnbaleAsync註解上通過@Import註解導入了AsyncConfigurationSelector類
接下來我們進入這個類
一看源碼,就發現繼承了AdviceModeImportSelector,其實這個類實現了ImportSelector接口,附上源碼
其實這個對於ImportSelector接口的實現就是解析註解的屬性,然後拿到一個AdviceMode,再調用一個模板方法selectImports,這個方法主要子類來實現,所以我們來看看AsyncConfigurationSelector的實現。
這個adviceMode是註解@EnableAaync註解中的屬性mode(),你可以自己翻一下,默認是PROXY,所以這個方法其實就是返回ProxyAsyncConfiguration類的全限定名,其實就是往容器中添加了ProxyAsyncConfiguration配置類。
我們進入這個配置類看一下
其實就是往容器中注入一個AsyncAnnotationBeanPostProcessor,通過名字可以看出這是一個BeanPostProcessor,也就是在bean的生命周期的某個節點來處理@Aysnc註解,如果有不懂BeanPostProcessor的同學可以看看Spring bean到底是如何創建的?(上)和 Spring bean到底是如何創建的?(下)這兩篇文章,裏面有詳細的說明。至於AsyncAnnotationBeanPostProcessor的實現我們就不再繼續深究了,有興趣的同學可以自行點進去看看。
所以說白了,@EnbaleAsync註解的主要作用就是往容器中添加一個可以住了@Async註解的AsyncAnnotationBeanPostProcessor,在bean創建的某個階段起到作用。
看完@EnableAsync註解的實現,你也可以仿照這個註解的實現來自己實現一個@Enable來實現某個特定的功能。
本文到這裡也就結束了。
如果我的文章對你有所幫助,還請幫忙點贊、在看、轉發一下,你的支持會激勵我輸出更高質量的文章,碼字不易,非常感謝!
如果你想聯繫我,歡迎關注我的個人的微信公眾號三友的java日記,公眾號會持續推送優質的技術文章,期待與你一起進步。
最近花了一個月的時間,整理了這套並發編程系列的知識點。涵蓋了 volitile、synchronized、CAS、AQS、鎖優化策略、同步組件、數據結構、線程池、Thread、ThreadLocal,幾乎覆蓋了所有的學習和面試場景,如圖。
文檔獲取方式:
鏈接://pan.baidu.com/s/129wZe3ywAUsjOqTU037Kmg
提取碼:aps9