




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第Spring源碼解析容器初始化構(gòu)造方法目錄前言構(gòu)造方法
前言
Spring框架被廣泛應(yīng)用于我們的日常工作中,但是很長時間以來我都是只會使用,不懂它的作用原理。通過最近一段時間的閱讀源碼,個人發(fā)現(xiàn)通過閱讀源碼,能夠幫助我們了解Spring的設(shè)計理念,并且對Java編程中的一些設(shè)計模式更加熟悉,所以記錄一下自己對Spring源碼的理解。
在開始進行源碼學(xué)習(xí)前,首先再回顧一下三種Spring編程風(fēng)格:
基于Schema,即通過xml標(biāo)簽的配置方式基于Annotation的注解技術(shù),使用@Component等注解配置bean基于JavaConfig,簡單來說就是使用@Configuration和@Bean進行配置
基于注解的方式需要通過xml或javaconfig來開啟。
在使用xml時,需要手動開啟對注解的支持:
context:annotation-config/
當(dāng)然,如果在xml中配置了掃描包,現(xiàn)在也可以光添加下面這一行,這行代碼中已經(jīng)包含了注解的開啟功能。
context:component-sacnbase-package="com"/
如果你使用的是下面AnnotationConfigApplicationContext這種方式,那么就不需要添加任何操作了,其中已經(jīng)包含了對注解的支持。
AnnotationConfigApplicationContextctx
=newAnnotationConfigApplicationContext(SpringConfig.class);
在實際使用過程中,三種方式是可以混合使用的,不存在沖突。按照下面這種方式作為AnnotationConfigApplicationContext傳入的配置文件,即可實現(xiàn)三種風(fēng)格的統(tǒng)一使用:
@Configuration
@ComponentScan("com")
@ImportResource("classpath:spring.xml")
publicclassSpringConfig{
}
之前也有小伙伴對我說,在開始學(xué)習(xí)Spring的時候,差點因為配置繁雜的xml被勸退,我也翻閱了一下網(wǎng)上spring入門的技術(shù)文章,確實很多還是停留在使用xml的方式上。但是其實如果你翻閱一下spring5的官方文檔,可以看出官方是推薦我們使用注解的方式的。
尤其是現(xiàn)在的SpringBoot更多的是基于注解,省略了很多配置的過程,對新手更加友好,降低了勸退率,所以本文將基于注解的方式進行源碼解析,另外再說明一下本文基于spring-framework-5.0.x源碼。
使用注解的方式初始化一個Spring環(huán)境,只需要下面一行代碼:
AnnotationConfigApplicationContextcontext
=newAnnotationConfigApplicationContext(SpringConfig.class);
如果看一下它的構(gòu)造方法,那么可以將它做的工作拆分為三步,為了便于理解可以寫成下面的形式,并分為三大模塊分別進行說明。
構(gòu)造方法
首先看一下AnnotationConfigApplicationContext的繼承關(guān)系:
AnnotationConfigApplicationContext繼承了GenericApplicationContext,那么我們先看GenericApplicationContext的構(gòu)造方法:
publicGenericApplicationContext(){
this.beanFactory=newDefaultListableBeanFactory();
}
在這里初始化了一個beanFactory的實現(xiàn)類DefaultListableBeanFactory,這就是我們常提到的spring中重要的bean工廠,這里面存放了很多非常重要的數(shù)據(jù)結(jié)構(gòu)。這里先列出比較重要的beanDefinitionMap,會在后面頻繁使用:
privatefinalMapString,BeanDefinitionbeanDefinitionMap=newConcurrentHashMap(256);
privatevolatileListStringbeanDefinitionNames=newArrayList(256);
在上面的這個beanDefinitionMap中就維護了beanName及BeanDefinition的對應(yīng)關(guān)系,beanDefinitionNames則是一個存放beanName的List。
從AnnotationConfigApplicationContext的構(gòu)造方法開始分析:
publicAnnotationConfigApplicationContext(){
this.reader=newAnnotatedBeanDefinitionReader(this);
this.scanner=newClassPathBeanDefinitionScanner(this);
}
首先實例化了一個AnnotatedBeanDefinitionReader對象,看一下AnnotatedBeanDefinitionReader的構(gòu)造函數(shù):
publicAnnotatedBeanDefinitionReader(BeanDefinitionRegistryregistry){
this(registry,getOrCreateEnvironment(registry));
}
那么,為什么在這能夠?qū)nnotationConfigApplicationContext對象作為BeanDefinitionRegistry傳入呢?
回頭看一下繼承關(guān)系那張圖,AnnotationConfigApplicationContext繼承了BeanDefinitionRegistry,并且最終實現(xiàn)了接口BeanFactory,BeanFactory可以說是Spring中的頂層類,它是一個工廠,能夠產(chǎn)生bean對象,提供了一個非常重要的方法getBean,會在后面講到。
到這,我們可以得出一個結(jié)論:
BeanDefinitionRegistry可以等同于AnnotationConfigApplicationContext,看做spring的上下文環(huán)境。
AnnotatedBeanDefinitionReader在實例化時,會調(diào)用registerAnnotationConfigProcessors方法。先看前半段代碼:
publicstaticSetBeanDefinitionHolderregisterAnnotationConfigProcessors(
BeanDefinitionRegistryregistry,@NullableObjectsource){
DefaultListableBeanFactorybeanFactory=unwrapDefaultListableBeanFactory(registry);
if(beanFactory!=null){
if(!(beanFactory.getDependencyComparator()instanceofAnnotationAwareOrderComparator)){
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
if(!(beanFactory.getAutowireCandidateResolver()instanceofContextAnnotationAutowireCandidateResolver)){
beanFactory.setAutowireCandidateResolver(newContextAnnotationAutowireCandidateResolver());
}
在這里先獲取在父類構(gòu)造函數(shù)中實例好的beanFactory,并為它填充一些屬性:
AnnotationAwareOrderComparator:主要用于排序,解析@order和@Priority注解ContextAnnotationAutowireCandidateResolver:提供處理延遲加載的功能
再看后半段代碼,下面生成了6個重要類的BeanDefinitionHolder,并存放到一個Set中:
SetBeanDefinitionHolderbeanDefs=newLinkedHashSet(8);
if(!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)){
RootBeanDefinitiondef=newRootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry,def,CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
if(!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)){
RootBeanDefinitiondef=newRootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry,def,AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
if(!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)){
RootBeanDefinitiondef=newRootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry,def,REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
//CheckforJSR-250support,andifpresentaddtheCommonAnnotationBeanPostProcessor.
if(jsr250Present!registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)){
RootBeanDefinitiondef=newRootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry,def,COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
//CheckforJPAsupport,andifpresentaddthePersistenceAnnotationBeanPostProcessor.
if(jpaPresent!registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)){
RootBeanDefinitiondef=newRootBeanDefinition();
try{
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
catch(ClassNotFoundExceptionex){
thrownewIllegalStateException(
"Cannotloadoptionalframeworkclass:"+PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,ex);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry,def,PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
if(!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)){
RootBeanDefinitiondef=newRootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry,def,EVENT_LISTENER_PROCESSOR_BEAN_NAME));
if(!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)){
RootBeanDefinitiondef=newRootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry,def,EVENT_LISTENER_FACTORY_BEAN_NAME));
returnbeanDefs;
}
這里是使用RootBeanDefinition來將普通類轉(zhuǎn)換為BeanDefinition,并進一步封裝成BeanDefinitionHolder。封裝成BeanDefinitionHolder的操作在registerPostProcessor方法中:
privatestaticBeanDefinitionHolderregisterPostProcessor(
BeanDefinitionRegistryregistry,RootBeanDefinitiondefinition,StringbeanName){
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName,definition);
returnnewBeanDefinitionHolder(definition,beanName);
}
通過registerBeanDefinition方法將BeanDefinition注冊到spring環(huán)境
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- JG/T 3064-1999鋼纖維混凝土
- DZ/T 0269-2014地質(zhì)災(zāi)害災(zāi)情統(tǒng)計
- DZ/T 0078-1993固體礦產(chǎn)勘查原始地質(zhì)編錄規(guī)定
- DZ/T 0057-1993水文水井鉆探鉆粒鉆頭
- CJ/T 262-2007給水排水用直埋式閘閥
- CJ/T 208-2005可曲撓橡膠接頭
- 二級計算機考試易錯點分析及試題
- Msoffice入門知識綜合問題與試題
- 社會工作者發(fā)展心理學(xué)基礎(chǔ)試題及答案
- 社會工作者心理咨詢技巧試題及答案
- 2024年成人高考成考(高起專)語文試題與參考答案
- 《高危新生兒分類分級管理專家共識(2023)》解讀
- iso220002024食品安全管理體系標(biāo)準(zhǔn)
- 2025高考物理步步高同步練習(xí)選修1第一章 動量章末檢測試卷(一)含答案
- 軍人優(yōu)待金委托書
- 2024年廣東省廣州市中考英語試卷附答案
- 大學(xué)生英語四級真題模擬試卷5份
- 2024年江蘇省蘇州市中考生物試卷(含答案)
- 山東省淄博市臨淄區(qū)2023-2024學(xué)年七年級下學(xué)期期末地理試題
- 大學(xué)《醫(yī)學(xué)統(tǒng)計學(xué)》期末復(fù)習(xí)章節(jié)知識點、考點總結(jié)
- 2024年中考理化生實驗操作考試安全應(yīng)急預(yù)案
評論
0/150
提交評論