spring啟動(dòng)分兩個(gè)階段
1、配置文件解析妈拌、注解解析階段, 生產(chǎn) BeanDefinition對象? spring配置文件中使用的占位符替換工作就是在這個(gè)階段完成的? ? (數(shù)據(jù)源的配置)
2蓬蝶、spring用之前產(chǎn)生的BeanDefinition對象完成bean的初始化和組裝工作
? 比如 事務(wù)尘分,proxy等就是在這個(gè)階段完成的
本文我只想縷清其大致過程,不關(guān)注具體實(shí)現(xiàn)細(xì)節(jié)丸氛,大致過程弄清楚了培愁,其余細(xì)節(jié)有興趣可以去翻翻詳細(xì)源碼
下面以springboot的啟動(dòng)過程為例縷縷以上兩個(gè)過程,
?我們知道啟動(dòng)springboot項(xiàng)目很簡單缓窜,初始化SpringApplication對象定续,并調(diào)用它的run方法
進(jìn)入到run方法
圖中
標(biāo)識(shí)1主要記錄容器啟動(dòng)時(shí)長,并打印日志
標(biāo)識(shí)2做了一些前置的準(zhǔn)備工作禾锤,大致了解一下就可以了
標(biāo)識(shí)3用來刷新容器私股,此處我們重點(diǎn)分析,跟進(jìn)去最終發(fā)現(xiàn)調(diào)用的是AbstractApplicationContext的refresh方法
1恩掷、this.postProcessBeanFactory(beanFactory) 跟進(jìn)去是空實(shí)現(xiàn)倡鲸,留給子類自己去實(shí)現(xiàn)
2、this.invokeBeanFactoryPostProcessors(beanFactory) 調(diào)用所有的BeanFacotryPostProcessor黄娘,其中ConfigurationClassPostProcessor值得重點(diǎn)關(guān)注峭状,后續(xù)講到
3、 this.registerBeanPostProcessors(beanFactory)注冊BeanPostProcessors到容器中
4寸宏、this.initMessageSource();初始化messageSource
5宁炫、initApplicationEventMulticaster();?初始化 事件分發(fā)器
6、onRefresh(); 通知子類刷新容器
7氮凝、registerListeners();?注冊事件監(jiān)聽器
8羔巢、finishBeanFactoryInitialization(beanFactory);初始化單例對象
9、finishRefresh();收尾工作,初始化LifecycleProcessor并調(diào)用器onRefresh方法
第一步看是怎么完成配置類的加載竿秆、解析启摄、創(chuàng)建BD對象并注冊到容器中的
我們進(jìn)入到invokeBeanFactoryPostProcessors方法里面
我們看到調(diào)用了PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法其中通過this.getBeanFactoryPostProcessors()獲取到前面準(zhǔn)備好的BeanFactoryPostProcessors列表跟進(jìn)去瞧瞧
有個(gè)很顯眼的PostProcessor對象BeanDefinitionRegistryPostProcessor調(diào)用了他的postProcessBeanDefinitionRegistry方法跟進(jìn)去發(fā)現(xiàn)調(diào)用其子類實(shí)現(xiàn)ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry
processConfigBeanDefinitions看到這個(gè)方法心里就有譜了,跟進(jìn)去代碼比較多幽钢,但是可以看到其中非常重要的一段代碼
1歉备、首先實(shí)例化ConfigurationClassParser對象并調(diào)用其parse方法用來解析 Configuration配置類并將其存放在內(nèi)部的一個(gè)Map對象configurationClasses中以備下一步使用
2、實(shí)例化ConfigurationClassBeanDefinitionReader調(diào)用其loadBeanDefinitions方法并將上一步解析得到的Map對象的keySet作為參數(shù)傳入
遍歷ConfigurationClass列表并調(diào)用loadBeanDefinitionsForConfigurationClass方法如下
不管怎么說此處就是分析ConfigurationClass并將ConfigurationClass所描述的配置類構(gòu)建成BeanDefinition對象并注冊到容器中匪燕,這里說的都是Configuration注解的類蕾羊,那我們還有很多Component,Service帽驯,Controller等注解的類呢龟再,它們是怎么加載和解析的呢?
我們再來看看ConfigurationClassParser的parser方法最后調(diào)用doProcessConfigurationClass
掃描ComponentScans定義下的所有類componentScanParser.parse()方法解析成BeanDefinitionHolder集合最后又調(diào)用processConfigurationClass方法接上前面的流程完成BeanDefintion的注冊尼变,到此完成上述過程中的第一步
再來看第二步實(shí)例化及初始化Bean并將Bean注冊到容器中的過程利凑,通過代碼的跟入發(fā)現(xiàn)都調(diào)用了AbstractBeanFactory的getBean方法,順著一直跟進(jìn)到getSingleton方法嫌术,終于在里面找到addSingleton方法將Bean的名稱和對象傳進(jìn)來哀澈,看看下面這段代碼
首先在緩存Map中獲取,如果為空則調(diào)用singletonFactory.getObject()方法創(chuàng)建一個(gè)新對象度气,最后如果是新創(chuàng)建的對象則調(diào)用addSingleton進(jìn)行注冊割按,存儲(chǔ)到本地的Map對象中,然后等我們調(diào)用context.getBean蚯嫌,其實(shí)就是在這個(gè)Map對象中獲取的
在創(chuàng)建新對象的時(shí)候會(huì)調(diào)用initializeBean方法我們來看看這個(gè)方法的實(shí)現(xiàn)
這里可以看到獲取所有的BeanPostProcessor,并調(diào)用postProcessBeforeInitialize()和postProcessAfterInitialization()方法對bean進(jìn)行增強(qiáng)處理丙躏。
總結(jié)
簡單的說第一階段就是加載配置類文件择示,然后調(diào)用解析器解析配置文件生成BeanDefinition對象,并調(diào)用BeanFactoryPostProcessor進(jìn)行處理之后存儲(chǔ)在Map中
然后第二階段根據(jù)BeanDefinition的定義通過反射進(jìn)行Bean的實(shí)例化晒旅,并在初始化工作中調(diào)用BeanPostProcessor進(jìn)行增強(qiáng)和組裝工作栅盲。
好了,這篇文章就到這里了废恋。