16 張圖解鎖 Spring 的整體脈絡(luò)
今天來梳理下 Spring 的整體脈絡(luò)啦,為后面的文章做個(gè)鋪墊~
話說咱們一直都在用這個(gè) Spring ,你們對(duì)它的感受是啥呀?還是說說不出來 哈哈
4ye 的感覺也是零零散散的,而且印象中一直都在用 Springboot ,不用再配置一堆東西呀,管理依賴啥的,方便太多了。
所以借此機(jī)會(huì)簡(jiǎn)單梳理下其中的一些脈絡(luò),這樣去看源碼就有條理多啦,更能知道一些擴(kuò)展點(diǎn)的使用等:stuck_out_tongue_closed_eyes:
目錄
本文會(huì)先大概介紹下這些知識(shí)點(diǎn) :point_down:
印象中的 Spring
腦海中有這么一條公式:
:point_right: IOC = 工廠模式 + XML + 反射
:point_right: 而 DI , AOP , 事務(wù) 等也都在 XML 中很直觀的表現(xiàn)出來
雖然我們現(xiàn)在大部分用這個(gè)注解來代替,但是原理還是基本一樣的:pig2:
注解使用起來很方便,但是學(xué)習(xí)的話,還是建議先通過這個(gè) XML ,畢竟結(jié)構(gòu)性的文檔,有層次感,可以留下更深的印象~ :smile:
小小Spring
把 Spring 濃縮一下,就有了這么一點(diǎn)小東西:pig2:
想了下,我們用 Spring ,其中最主要的一點(diǎn),就是用它來幫我們管理,創(chuàng)建這個(gè) Bean 。
那么先從源頭看起 —— Bean 從哪來 (@_@;)
Bean 解析流程
如圖所示,就是通過 解析器 ,對(duì)我們的 XML 文件或者注解進(jìn)行解析,最后將這些信息封裝在 BeanDefinition 類中,并通過 BeanDefinitionRegistry 接口將這些信息 注冊(cè) 起來,放在 beanDefinitionMap 變量中, key : beanName , value :BeanDefinition
簡(jiǎn)單看看 BeanDefinition 中的屬性叭
BeanDefinition
-
beanClass : bean 的類型 ,實(shí)例化時(shí)用的 :pig2:
-
scope : 作用范圍有 singleton,prototype
-
isLazy : 懶加載 ,true 的話 會(huì)在 getBean 時(shí)生成,而且 scope 的 prototype 無效,false 在 Spring 啟動(dòng)過程中直接生成
-
initMethodName : 初始化方法,當(dāng)然是初始化時(shí)調(diào)用:pig2:
-
primary : 主要的,有多個(gè) Bean 時(shí)使用它
-
dependsOn : 依賴的Bean,必須等依賴Bean 創(chuàng)建好才可以創(chuàng)建
PS: @Component ,@Bean , 都會(huì)被解析成 BeanDefinition
反射
有了原料后呢, 咱 們?cè)賮砜纯催@個(gè) 工廠 BeanFactory
先簡(jiǎn)單想一想這個(gè)工廠要怎么創(chuàng)建這個(gè) Bean 呢?
沒錯(cuò),肯定就是這個(gè) 反射 啦 :smile:
那么,結(jié)合我們從原料中獲取的重要屬性之一的 beanClass ,我們可以畫出這么一張圖 :point_down:
那么我們?cè)賮砜纯催@個(gè) BeanFactory 叭 :smile:
BeanFactory
先來看看 作為IOC 容器的 根接口 的 BeanFactory 提供了什么方法吧:point_down:
主要是這個(gè) getBean 方法,以及 別名獲取 , 類型獲取 方法和其他一些判斷方法如 : 單例 , 多例 , 類型匹配 , 包含bean
我們來簡(jiǎn)單看看它的子接口都有哪些叭~:smile:
這里分享個(gè)小技巧叭:pig2:
看源碼的時(shí)候,一般就直接看這個(gè) 默認(rèn) 接口 如這里的 DefaultListableBeanFactory
基本上看個(gè)類名就知道大概作用了,那么先對(duì)號(hào)入座下:point_down:
ListableBeanFactory
:point_right: 遍歷 bean
HierarchicalBeanFactory
:point_right: 提供 父子關(guān)系,可以獲取上一級(jí)的 BeanFactory
ConfigurableBeanFactory
:point_right: 實(shí)現(xiàn)了 SingletonBeanRegistry ,主要是 單例Bean的注冊(cè),生成
AutowireCapableBeanFactory
:point_right: 和自動(dòng)裝配有關(guān)的
AbstractBeanFactory
:point_right: 單例緩存,以及 FactoryBean 相關(guān)的
ConfigurableListableBeanFactory
:point_right: 預(yù)實(shí)例化單例Bean,分析,修改 BeanDefinition
AbstractAutowireCapableBeanFactory
:point_right: 創(chuàng)建 Bean ,屬性注入,實(shí)例化,調(diào)用初始化方法 等等
DefaultListableBeanFactory
:point_right: 支持單例Bean ,Bean別名 ,父子BeanFactory,Bean 類型轉(zhuǎn)化 ,Bean 后置處理,F(xiàn)actoryBean,自動(dòng)裝配等
是不是非常豐富 :smile:
FactoryBean
FactoryBean ,它本身就是個(gè) Bean,算是小工廠 ,歸 BeanFactory 這個(gè)大工廠管理的。
可以看到它就只有三個(gè)方法
-
getObject() 獲取對(duì)象
-
isSingleton() 單例對(duì)象
-
getObjectType() 返回的是 Bean 對(duì)象的類型
相比大工廠 BeanFactory 少了特別多東西,沒有嚴(yán)格的 Bean 生命周期流程
在 :point_right: 《三分鐘快速了解Spring中的工廠模式》 一文中有介紹到 :smile:
FacotryBean 對(duì)象本身也是一個(gè)Bean,是一個(gè)小工廠,可以生產(chǎn)另外的 Bean
BeanFactory 是 Spring 容器的根接口,是大工廠,生產(chǎn)各種各樣的Bean
beanName 就是正常對(duì)象
“&”+beanName , 獲取的是實(shí)現(xiàn)了該接口的 FacotryBean 工廠對(duì)象
大致如下 :point_down:
ApplicationContext
我們?cè)賮砜纯催@個(gè) ApplicationContext
可以看到它擴(kuò)展了很多功能,除了 BeanFactory ,它還可以 創(chuàng)建 , 獲取 Bean ,以及處理 國際化 , 事件 , 獲取資源 等
-
EnvironmentCapable 獲取 環(huán)境變量 的功能,可以獲取到 操作系統(tǒng)變量 和 JVM 環(huán)境變量
-
ListableBeanFactory 獲取所有 BeanNames,判斷某個(gè) BeanName 是否存在 BeanDefinition 對(duì)象,統(tǒng)計(jì) BeanDefinition 對(duì)象,獲取某個(gè)類型對(duì)應(yīng)的所有 beanNames 等功能
-
HierarchicalBeanFactory 獲取父 BeanFactory ,判斷某個(gè) name 是否存在 bean 對(duì)象的功能
-
MessageSource 國際化功能 ,獲取某個(gè)國際化資源
-
ApplicationEventPublisher 事件發(fā)布功能 (重點(diǎn))
-
ResourcePatternResolver 加載,獲取資源的功能 ,這里的資源可能是文件,圖片 等某個(gè)URL資源都可以
還有這三個(gè)重要的類:point_down:,就不一一介紹先啦:smile:
-
ClassPathXmlApplicationContext
-
AnnotationConfigApplicationContext
-
FileSystemXmlApplicationContext
趕緊來看看這個(gè)核心叭!
IOC 容器
當(dāng)然,這時(shí)候出場(chǎng)的肯定是 IOC 啦。
我們都知道 IOC 是 控制反轉(zhuǎn) ,但是別忘了 容器 這個(gè)詞,比如 **容器的根接口 **BeanFactory , 容器的實(shí)現(xiàn) :point_down:
-
ClassPathXmlApplicationContext
-
AnnotationConfigApplicationContext
-
FileSystemXmlApplicationContext
同時(shí)我們要注意這里無處不在的 后置處理器 xxxPostProcessor :pig:
這個(gè)是 Spring 中擴(kuò)展性強(qiáng)的原因了!
我們可以在各個(gè)過程中合理應(yīng)用這些 PostProcessor 來擴(kuò)展,或者修改 Bean 定義信息等等
可以看到在這個(gè)容器中,完成了 Bean 的初始化,而這個(gè)過程還有很多細(xì)節(jié) ,請(qǐng)往下看看:point_down:
DI 到時(shí)寫 屬性填充 時(shí)再介紹:pig:
BeanFactory 后置處理器
作為 IOC 容器根接口的 BeanFactory ,有著非常高的擴(kuò)展性,比如最開始獲取原料 BeanDefinition 時(shí),就出現(xiàn)了兩個(gè)針對(duì) BeanFactory 工廠的后置處理器 :point_down:
BeanDefinitionRegistryPostProcessor
通過該接口,我們可以自己掌控我們的 原料 ,通過 BeanDefinitionRegistry 接口去 新增 , 刪除 , 獲取 我們這個(gè) BeanDefinition
BeanFactoryPostProcessor
通過該接口,可以在 實(shí)例化對(duì)象前 ,對(duì) BeanDefinition 進(jìn)行修改 , 凍結(jié) , 預(yù)實(shí)例化單例Bean 等
經(jīng)過上面層層阻礙后,我們最終會(huì)來到目標(biāo)方法 getBean ,將原料投入生產(chǎn),最終獲取一個(gè)個(gè) Bean 對(duì)象出來
那么隨之而來的就是這個(gè) Bean 的生命周期啦 :smile:
Bean 生命周期
Bean 的創(chuàng)建和管理有 標(biāo)準(zhǔn)化的流程 !
這里在我們的工廠 BeanFactory 中寫得很清楚 :point_down:
總共 14 個(gè)步驟,是不是一下子就清晰多了:smile:
在看這部分的源碼時(shí),要多注意兩個(gè)英文單詞 :stuck_out_tongue_closed_eyes:
-
實(shí)例化:point_right: Instantiation
-
初始化:point_right: Initialization
ps: 別看快搞錯(cuò)了 哈哈:stuck_out_tongue_closed_eyes:
仔細(xì)閱讀上面這14個(gè)步驟,會(huì)發(fā)現(xiàn)前面 8 個(gè)都是 Aware 接口,而他們的作用也很簡(jiǎn)單,就是獲取 xxAware 這個(gè)單詞的前綴 xx :smile:
比如我們?cè)谏衔?:point_right: 《三分鐘快速上手Spring事件機(jī)制》 中提到的事件發(fā)布器 ApplicationEventPublisher ,只要你實(shí)現(xiàn)了 ApplicationEventPublisherAware 接口,就可以 獲取 事件發(fā)布器 ApplicationEventPublisher !
Bean 后置處理器
在實(shí)例化 和 初始化流程中,把這個(gè)Bean 的后置處理器 BeanPostProcessor 安排上,就得到下圖啦 :point_down:
這里留意下 實(shí)例化 有擴(kuò)展點(diǎn) InstantiationAwareBeanPostProcessor , 初始化 擴(kuò)展點(diǎn) BeanPostProcessor 就非常多啦,我們主要來關(guān)注下這個(gè) AOP
AOP
那么 AOP 是在哪個(gè)步驟代理對(duì)象的呢?:point_down:
可以在 AbstractAutoProxyCreator 類中看到 :point_down:
總結(jié)
本文就先介紹到這里啦:pig2:
主要介紹了 Spring 里面的這些脈絡(luò),方便小伙伴們對(duì)它有個(gè)整體的印象先~
再介紹其中的一些擴(kuò)展點(diǎn),比如從源材料的 BeanFactoryPostprocessor ,到產(chǎn)物 Bean 的 BeanPostprocessor 。
實(shí)例化,初始化的順序,Bean的生命周期,以及 BeanFactory 及子類擴(kuò)展的功能,再到 ApplicationContext 的功能。
還有這個(gè)核心機(jī)制: 工廠+XML+反射 ,以及引出下文要說的 AOP 發(fā)生的地方 。