spring?Bean創(chuàng)建的完整過(guò)程記錄
前言
復(fù)習(xí)一下spring實(shí)現(xiàn)IOC的源碼流程準(zhǔn)備工作:
?強(qiáng)烈建議大家從git上拉取spring源碼來(lái)學(xué)習(xí)Spring源碼。因?yàn)槔锩嫦噍^于IDEA生成的會(huì)有注釋?zhuān)锩嬗械姆椒〞?huì)有注釋看起來(lái)會(huì)省力一點(diǎn)。
?以下都是用5.0.2版本來(lái)做闡述。
bean創(chuàng)建的流程圖
寫(xiě)在前面:建議大家一定要自己用實(shí)例跑一遍,做好記錄。如果只是看看會(huì)非常抽象。此流程圖作為梗概,便于加強(qiáng)記憶和理解,新手或無(wú)基礎(chǔ)的有個(gè)印象即可。等跟隨本文走通一遍,在回過(guò)頭看這個(gè)圖,或許會(huì)有收獲
源碼走一遍bean的定義這是我的bean目錄結(jié)構(gòu),只是做一個(gè)例子
獲取核心容器對(duì)象,bean最后都會(huì)放在此容器對(duì)象中
* ApplicationContext的三個(gè)實(shí)現(xiàn)類(lèi) * ClassPathXmlApplicationContext 它可以加載類(lèi)路徑下的配置文件,要求必須在類(lèi)路徑下 * FileSystemXmlApplicationContext 可以加載任意路徑下的配置文件,必須有訪問(wèn)權(quán)限 * AnnotationConfigApplicationContext 用于讀取注解創(chuàng)建容器的 這里我用ClassPathXmlApplicationContext來(lái)做演示 public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); } }
快速開(kāi)始
建議用IDEA的debug模式來(lái)觀察Spring的IOC過(guò)程
進(jìn)入到此類(lèi)的構(gòu)造方法中
查看setConfigLocations,就是將配置文件加載到configLocations里去
向下執(zhí)行,查看refresh()
this.prepareRefresh(): 此方法是準(zhǔn)備工作,大家感興趣可以點(diǎn)進(jìn)去看一下,可以看到里面是獲取時(shí)間,獲取環(huán)境信息的一些設(shè)置。
this.obtainFreshBeanFactory(): 這一步是創(chuàng)建beanFactory,并且讀取Bean的信息,源碼注釋中還有寫(xiě)到
// Tell the subclass to refresh the internal bean factory.會(huì)告訴子類(lèi)去刷新內(nèi)部bean工廠
this.refreshBeanFactory:
* This implementation performs an actual refresh of this context's underlying * bean factory, shutting down the previous bean factory (if any) and * initializing a fresh bean factory for the next phase of the context's lifecycle. 這個(gè)實(shí)現(xiàn)類(lèi)的方法會(huì)刷新容器中的beanFactory,關(guān)閉之前存在的并且初始化新的beanFactory
利用this.createBeanFactory() 創(chuàng)建了一個(gè)beanFactory,類(lèi)型為DefaultListableBeanFactory
這個(gè)類(lèi)接著往下走:this.loadBeanDefinitions(beanFactory);
* Load bean definitions into the given bean factory, typically through * delegating to one or more bean definition readers. 這個(gè)方法會(huì)將beandefinitionsReader讀取到的bean definitions放入bean工廠,我們以上提出的三種 注入方式都會(huì)走到這里,將bean信息丟進(jìn)去
返回上述 refresh()
this.prepareBeanFactory(beanFactory); 設(shè)置和忽略一些對(duì)象值
this.postProcessBeanFactory(beanFactory); 空方法可自定義擴(kuò)展
this.invokeBeanFactoryPostProcessors(beanFactory);
* Instantiate and invoke all registered BeanFactoryPostProcessor beans, * respecting explicit order if given. * <p>Must be called before singleton instantiation. 實(shí)例化所有beanFactory組件
registerBeanPostProcessors(beanFactory);
Instantiate and register all BeanPostProcessor beans, //先注冊(cè)再調(diào)用
initApplicationEventMulticaster(); 觀察者模式監(jiān)聽(tīng)器, 監(jiān)聽(tīng)組件的相關(guān)狀態(tài),并決定相關(guān)調(diào)用方法。
finishBeanFactoryInitialization(beanFactory); 重要??!
* Finish the initialization of this context's bean factory, * initializing all remaining singleton beans. 完成了容器bean factory的初始化,并且初始化其他的bean單例對(duì)象
beanFactory.preInstantiateSingletons(); 實(shí)例化方法
此方法最后this.getBean(beanName)
繼續(xù)
Return an instance, which may be shared or independent, of the specified bean. 注釋已經(jīng)很清楚了,此方法會(huì)返回一個(gè)實(shí)例,就是我們的bean對(duì)象
進(jìn)入到createBean方法中
繼續(xù)進(jìn)入
繼續(xù)進(jìn)入
Instantiate the given bean using its default constructor. 這個(gè)方法注釋說(shuō)明了實(shí)例化對(duì)象是用構(gòu)造器完成的
繼續(xù)看他如何構(gòu)造的
ca 就是Constructor,從這里我們基本可以看出容器內(nèi),bean對(duì)象的實(shí)例化 是利用反射的基本原理,獲取類(lèi)構(gòu)造器,然后newInstance來(lái)實(shí)現(xiàn)的
以上就是bean對(duì)象實(shí)例化的基本過(guò)程,下面是實(shí)例化完成后的初始化過(guò)程
回到這里,實(shí)例化完成后
注釋說(shuō)明了在populateBean完成bean的初始化
繼續(xù)
會(huì)看到在此方法里會(huì)調(diào)用前置和后置處理器來(lái)初始化Bean
以上就完成了bean的實(shí)例化過(guò)程,文章開(kāi)頭的那個(gè)圖剛開(kāi)始有點(diǎn)懵,但是一旦跑完一遍bean的實(shí)例化過(guò)程,再次結(jié)合圖,就清晰了很多。本文只是簡(jiǎn)單的跟隨debug順序,完整的走了一遍bean實(shí)例化的過(guò)程,還有特殊情況并沒(méi)有討論,后期會(huì)重新用新文章再來(lái)拓展。
如有不足還請(qǐng)指正。
總結(jié)
到此這篇關(guān)于spring Bean創(chuàng)建的文章就介紹到這了,更多相關(guān)Spring Bean創(chuàng)建過(guò)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring?IOC容器Bean注解創(chuàng)建對(duì)象組件掃描
- 詳談spring中bean注入無(wú)效和new創(chuàng)建對(duì)象的區(qū)別
- JavaBean和SpringBean的區(qū)別及創(chuàng)建SpringBean方式
- Spring整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案
- Spring-AOP自動(dòng)創(chuàng)建代理之BeanNameAutoProxyCreator實(shí)例
- Spring容器的創(chuàng)建過(guò)程之如何注冊(cè)BeanPostProcessor詳解
- Spring?Bean創(chuàng)建的另一條捷徑
相關(guān)文章
Eclipse中Debug時(shí)鼠標(biāo)懸停不能查看變量值解決辦法
這篇文章主要介紹了Eclipse中Debug時(shí)鼠標(biāo)懸停不能查看變量值解決辦法,以及分享了一個(gè)簡(jiǎn)單補(bǔ)全代碼的方法,還是比較不錯(cuò)的,需要的朋友可以參考下。2017-11-11如何使用jmeter錄制瀏覽器Https請(qǐng)求過(guò)程圖解
這篇文章主要介紹了基于jmeter錄制瀏覽器Https請(qǐng)求過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04java?啟動(dòng)參數(shù)?springboot?idea詳解
這篇文章主要介紹了java?啟動(dòng)參數(shù)?springboot?idea的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09Spring Boot異步調(diào)用@Async過(guò)程詳解
這篇文章主要介紹了Spring Boot異步調(diào)用@Async過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11Java實(shí)現(xiàn)學(xué)生信息管理界面
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)學(xué)生信息管理界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06SpringCloud?Gateway實(shí)現(xiàn)API接口加解密
這篇文章主要為大家介紹了SpringCloud?Gateway如何實(shí)現(xiàn)API接口加解密的,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定的幫助,需要的可以參考一下2022-06-06