spring源碼深度解析-1核心實現


xml配置文件的讀取:
1:通過集成字AbstractBeanDefinitionReader中的方法,來使用ResourceLoader將資源文件路徑轉換為對應的Resource文件
2:通過DocumentLoader對Resource文件驚醒轉換,將Resource文件轉換為Document文件
3:通過實現借口BeanDefinitionDocumentReader的DefaultBeanDefinitionDocumentReader類對Document進行解析,bingshiyongBeanDeifinitionParserDelegete對Element進行解析

當A中有屬性B那么當spring在獲取a的bean的時候如果屬性b還沒有初始化,那么spring會自動初始化b。但是某些情況下,b不會被初始化,其中一種情況b實現了BeanNameAware借口

this.reader.loadBeanDefinitions(resource)
1:封裝資源文件,當進入XmlBeanDefinitionReader后首先對參數Resource使用EncodeResource類進行封裝
2:獲取輸入流,從Resource中獲取對應的InputStream並構造InputSrource
3:通過構造的InputSource實例和Resource實例繼續調用函數doLoadBeanDefinitions

doLoadBeanDefinitions(inputSource, encodedResource.getResource());
1:獲取對XML文件的驗證模式
2:獲取XML文件,並得到對應的Document
3:根據返回的Document注冊Bean信息

XML驗證模式分為DTD(Document Type Definition)、XSD(Xml Schemes Definition)

驗證模式的讀取:getValidationModeForResource(Resource resource)
1__如果設定驗證模式,就使用設定的。沒設定就自動檢測

自動檢測:detectValidationMode(resource) 又調用了XmlValidationModeDetector的檢測方法
spring緝拿測驗蒸饃是的辦法就是判斷是否包含DOCTYPE,包含就是DTD,否則就是XSD

2__獲取Document: XmlBeanFactoryReader對於文檔的讀取將誒DocumentLoader去執行,DocumentLoader是個借口,交給DefaultDocumentLoader
DefaultDocumentLoader:loadDocument(InputSource inputSource, EntityResourlver entityResoulver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware);
通過SAX解析XML。創建DocumentBuilderFactory,在通過他創建DocumentBuilder,進而解析inputSource來返回Document對象

EntityResolver是通過getEntityResourlver()獲取的返回值
EntityResolver用法:
對於解析一個XML,SAX首先讀取給xml文檔上的生命,根據生命去尋找對應的DTD定義,一邊對文檔進行一個驗證。默認的尋找規則,及通過網路(實際上就是生命的DTD的URI)來下載相應的DTD生命,並進行認證,下載的過程是一個漫長的過程,而且當網不可用時報錯,就是因為DTD聲明沒被找到的原因。
EntityResolver的作用是項目本身就可以提供一個如何尋找DTD生命的方法,及由程序來實現尋找DTD聲明的過程,比如將DTD文件放到項目的某處,在實現時直接將此文檔直接返回給SAX即可。避免通過網絡來尋找。

3__解析及注冊 BeanDefinitions:XmlBeanDefinitionReader:registerBeanDefinitions(Document doc, Resource resource)
doc是上步loadDocument獲取的
BeanDefinitionDocumentReader是個借口由createBeanDefinitionDocumentReader()獲取的類型實際為DefaultBeanDefinitionDocumentReader,進入registerBeanDefinitions()方法
這個方法的重要目的之一就是獲取root(Element類型),便於再次將root作為參數繼續BeanDefinition的注冊。

-->doRegisterBeanDefinitions(root) 以前一直是解析xml的准備階段,這個方法真正的開始解析了
首先對profile處理,可是preProcessXml(root)或者postProcessXml(root)的代碼是空的。在DefaultBeanDefinitionDocumentReader中並沒有final,面向集成,集成DefaultBeanDefinitionDocumentReader的子類如果需要在解析xml前后做一些操作,只需重寫這兩個方法

profile屬性的作用:方便在配置文件中配置兩套配置:dev、production

解析並注冊BeanDefinition
--> parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
import標簽、alias標簽、bean標簽、beans標簽。
bean標簽最復雜,直接看bean標簽
-->processBeanDefinition(ele, delegate)
1:delegate.parserBeanDefinitionElement(ele)
首先委托BeanDefinitionHolder類型的實例bdHolder,經過這個方法后,bdHolder實例已經包含我們配置文件的配置的各種屬性了,例如class、name、id、alias之類的屬性
2:delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)
當返回的bdHolder部位空的情況下若存在默認標簽的子節點下在有自定義屬性,還需要在此對自定義的標簽進行解析
3:BeanDefinitionReaderUtils.registerBeanDefinition(hbHoder, getReaderContext(), getRegistry())
解析完成后,需要對解析后的bdHolder進行注冊,同樣,注冊操作委托給了BeanDefinitionReaderUtils的registerBeanDefinition方法
4:getReanderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))
最后發出響應事件,通知相關的監聽器,這個bean已經加載完成了

1_delegate.parserBeanDefinitionElement(ele)
--> delegate.parserBeanDefinitionElement(ele, null)
(1)提取元素中的id以及name屬性
(2) parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean)
進一步解析其他所有屬性並統一封裝至GenericBeanDefinition類型的實例中
(3)如果檢測到bean沒有指定beanName,那么使用默認規則為此Bean生成beanName
(4)將獲取到的信息封裝到BeanDefinitionHolder的實例中

2__ parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean):對其他標簽解析
(1)___createBeanDefinition(className, parent)
創建用於承載屬性的AbstractBeanDefinition類型的GenericBeanDefinition

(2)__parseBeanDefinitionAttributes(ele, beanName, containingBean, bd) :返回值 AbstractBeanDefinition
硬編碼解析默認bean的各種屬性

(3)__parseMetaElements(ele, bd)
解析元數據

(4)___ parseLookupOverrideSubElements(ele, bd.getMethodOverrides())
解析lookup-method屬性

(5)___ parseReplaceMethodSubElements(ele, bd.getMethodOverrides())
解析replaced-method屬性

(6)___ parseConstructorArgElements(ele, bd)
解析構造函數參數

(7)___ parsePropertyElements(ele, bd)
解析property子元素

(8)___ perseQualifierElements(ele, bd)
解析qualifier子元素

1___ createBeanDefinition(className, parent)
BeanDefinition是一個接口,在spirng存在三種實現, RootBeanDefinition、ChildBeanDefinition以及GenericBeanDefinition。三種實現均繼承了AbstractBeanDefinition,BeanDefinition是配置文件<bean>元素標簽子啊容器中的內部表示形式。<bean>元素標簽擁有beanclass、scope、lazyinit等配置屬性, BeanDefinition則提供了相應的beanClass、scope、lazyInit屬性,BeanDefinition和<bean>中的屬性是一一對應的。其中RootBeanDefinition是最常用的實現類,BeanDefinition他對應一般性的bean元素標簽,GenericBeanDefinition是自2.5版本以后新家入黨bean文件配置屬性定義類一站式服務類。
在配置文件中可以定義父<bean>和子<bean>,父<bean>用RootBeanDefinition表示,而子<bean>用ChildBeanDefinition表示,沒有父<bean>的使用RootBeanDefinition表示。AbstractBeanDefinition對兩者共同的信息進行抽象
spring通過BeanDefinition將配置文件中的<bean>配置信息轉換容器的內部表示,並將這些Beandefinition注冊到BeandefinitionRegistry中。Spring容器的BeandefinitionRegistry就像是Spring配置信息內存數據庫,主要已map的形式保存,后續操作直接從BeandefinitionRegistry中讀取配置信息。
由此可知,要解析屬性首先要創建用於集成屬性的實例,也就是創建GenericBeanDefinition類型的實例。而代碼createBeanDefinition(className, parent)就是此功能

2___ parseBeanDefinitionAttributes(ele, beanName, containingBean, bd)解析各種屬性

6___ parseConstructorArgElements(ele, bd)
首先提取constructor-arg上比喲啊讀屬性(index、type、name)
如果配置中置頂index屬性,那么操作步驟如下:
解析constructor-arg的子元素
使用ConstructorArgumentValues.ValueHolder類型來封裝解析出來的元素
建type、name、和index屬性一並封裝在ConstructorArgumentValues.ValueHolder類型中並添加至當前Beandefinition的constructorArgumentValues的 indexedArgumentValues 屬性中

如果沒有置頂index屬性,那么操作步驟如下
解析constructor-art的子元素
使用ConstructorArgumentValues.ValueHolder類型來封裝解析出來的元素
建type、name、和index屬性一並封裝在ConstructorArgumentValues.ValueHolder類型中並添加至當前Beandefinition的constructorArgumentValues的 genericArgumentValues 屬性中

AbstractBeanDefinition屬性
至此xml所有的配置都可以在GenericBeanDefinition中找到,GenericBeanDefinition是子類大部分屬性都保存在AbstractBeanDefinition中。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {
private String scope = SCOPE_DEFAULT;

private boolean abstractFlag = false;

private boolean lazyInit = false;

private int autowireMode = AUTOWIRE_NO;

private int dependencyCheck = DEPENDENCY_CHECK_NONE;

private String[] dependsOn;

private boolean autowireCandidate = true;

private boolean primary = false;

private final Map<String, AutowireCandidateQualifier> qualifiers =
new LinkedHashMap<String, AutowireCandidateQualifier>(0);

private boolean nonPublicAccessAllowed = true;

private boolean lenientConstructorResolution = true;

private ConstructorArgumentValues constructorArgumentValues;

private MutablePropertyValues propertyValues;

private MethodOverrides methodOverrides = new MethodOverrides();

private String factoryBeanName;

private String factoryMethodName;

private String initMethodName;

private String destroyMethodName;

private boolean enforceInitMethod = true;

private boolean enforceDestroyMethod = true;

private boolean synthetic = false;

private int role = BeanDefinition.ROLE_APPLICATION;

private String description;

private Resource resource;
}

2__ delegate.decorateBeanDefinitionIfRequired(ele, bdHolder) --> decorateBeanDefinitionIfRequired(ele, bdHolder, null)
decorateBeanDefinitionIfRequired(Element ele,BeanDefinitionHolder bdHolder, BeanDefinition containingBd)
對程序默認的標簽的處理其實是直接略過的,因為默認標簽在上步已經處理完了,這里支隊自定義的標簽或者說對bean的自定義屬性感興趣。
這里將第三個參數設為null,其實第三個參數的含義是父類bean,當對某個潛逃配置進行分析時,這里需要傳遞父類beanDefinition。這里傳遞參數其實是用父類的scope屬性,以備子類沒有scope屬性時使用父類屬性,這里是頂層配置,所有為null。
--> decorateIfRequired(node, finalDefinition, containingBd)
decorateIfRequired(Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd)
獲取元素或者屬性的命名空間,找出自定義類型所對應的NamespaceHandler並進行下一步解析。

3__ BeanDefinitionReaderUtils.registerBeanDefinition(hbHoder, getReaderContext(), getRegistry()) 60頁
解析的beanDefinition都會被注冊到BeanDefinitionRegistry類型的實例registry中,而注冊分成了兩部分:
(1):通過beanName注冊 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())
(2):別名注冊 registry.registerAlias(beanName, aliase)

1___ registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
對於beanDefinition的注冊,beanDefinition直接放入map中,使用beanName作為key
(1)對AbstractBeanDefinition的效驗,此時的效驗是對於AbstractBeanDefinition的methodOverrides屬性的。
(2)對beanName已經注冊的情況的處理,如果設置了不允許bean的覆蓋,則需要拋出異常,否則直接覆蓋
(3)加入map緩存
(4)清除解析之前留下的對應beanName的緩存

2___ registerAlias(String name, String alisas)
(1)alias的beanName相同情況處理。如果相同,不處理並刪除原有的alias
(2)alias覆蓋。若aliasName已經使用並已經指向了另一beanName則需要用戶的設置進行處理
(3)alias循環檢查
(4)注冊alias

 

 

bean的加載 78頁
bf.getBean()
三個主要的方法 :
getSingleton(beanName)
getObjectForBeanInstance(sharedInstance, name, beanName, null)
createBean(beanName, mbd, args);

(1)轉換對應的beanName
出入的name可能是別名,也可能是FactoryBean
(1) 去處FactoryBean的修飾符,也就是如果name="&aa",那么首先去除&而使用name="aa"
(2) 取指定alias所表示的最終beanName。

(2)嘗試從緩存中加載單例
首先嘗試從緩存中加載,不成功嘗試從singletonFactories中加載。因為在創建單例bean的時候會存在依賴注入的情況,而在依賴的時候為了避免循環依賴,在spring中創建bean的原則是不等bean創建bean創建完成就會將創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建的時候需要依賴上一個bean則直接使用ObjectFactory。

(3)bean的實例化
如果從緩存中得到了bean的原始狀態,則需要對bean進行實例化。這里有必要強調一下,緩存中記錄的只是最原始的狀態,不一定是我們想要的。如:我們需要工廠bean,獲得的其實是原始的bean狀態,但我們真正想要的是工廠bean中factory-method方法中返回的bean,而getObjectForBeanInstance就是完成這個工作的。

(4)原型模式的依賴檢查
只有在單例情況下才會嘗試解決循環依賴,a中有b,b中有a。也就是isPrototypeCurrentlyInCreation(beanName)判斷為true

(5)檢測parentBeanFactory
代碼上,如果緩存沒有數據,直接轉到父類工廠上加載。
但是!containsBeanDefinition(beanName)判斷條件比較重要,檢測如果當前加載的xml配置文件中不包含beanName所對應的配置,就只能到parentBeanFactory去嘗試下了,然后在遞歸調用getBean方法

(6)將儲存xml配置文件的gergericBeanDefinition轉換為RootBeanDefinition
xml中讀取的信息都在GernericBeanDefinition中,但是所有bean的后續處理都在是針對於RootBeanDefinition,所以需要進行一個轉換。

(7)尋找依賴
因為bean的初始化過程可能會用到某些屬性,而這些屬性有可能是動態配置的,這個時候需要加載他所依賴的。所以在spring中,初始化一個bean的時候先初始化他所依賴的bean

(8)針對不痛的scope進行bean的創建
在spring中存在不痛的scope,默認的是singleton,其他的還有prototype,request之類的

(9)類型轉換
到這里,返回的bean已經基本結束了,通常改方法調用的requestType為空的,但是也可能存在這樣的情況,返回的bean其實是個string,但是requiredType卻傳入一個Integer,那么這步就會起作用了。


1
#########################################################
FactoryBean的使用比較有用(書的83頁,或者在網上搜搜看看) #
#########################################################

2 緩存中獲取單例bean
getSingleton(String beanName)
--> getSingleton(String beanName, boolean allowEarlyReference)
首先嘗試從singletonObjects里面獲取實例,如果獲取不到在從earlySingletonObjects里面獲取,如果還獲取不到,在嘗試從singletonFactories里面獲取beanName對應的ObjectFactory,然后在調用這個ObjectFactory的getObject來創建bean,並放到earlySingletonObjects里面去,並且從singletonFactories里面remove掉這個ObjectFactory,而對於后續的所有內存操作都只為了循環依賴檢查測試時候使用,也就是allowEarlyReference為true的情況下會使用
singletonObjects:用於保存BeanName和創建bean實例之間的關系,bean name --> beaninstance
singletonFactories:用於保存BeanName和創建bean的工廠之間的關系,bean name --> ObjectFactory
earlySingletonObjects:也是保存BeanName 和創建bean實例之間的關系,與singletonObjects的不同在於,當一個單例bean被放到這里面后,那么當bean還在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環利用。
registerdSingletons:用來保存當前所有已經注冊的bean

3 從bean的實例中獲取對象 getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd)
得到bean的實例后要做的第一件事就是驗證當前的bean是否是FactoryBean類型的bean,如果是,調用改bean對應的FactoryBean實例中的getObject作為返回值。
如果從緩存中得到了bean的原始狀態,則需要對bean進行實例化。這里有必要強調一下,緩存中記錄的只是最原始的狀態,不一定是我們想要的。如:我們需要工廠bean,獲得的其實是原始的bean狀態,但我們真正想要的是工廠bean中factory-method方法中返回的bean,而getObjectForBeanInstance就是完成這個工作的。
(1)對FactoryBean的正確性的驗證
(2)對非FactoryBean不做任何處理
(3)對bean進行轉換
(4)將從Factory中解析bean的工作委托給getObjectFromFactoryBean
--> getObjectFromFactoryBean(FacotyBean facotry, String branName, boolean shoudPostProcess)
在doGetObjectFromFactoryBean()中獲取。保證返回的bean是單例的。
--> doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
上面說過如果bean聲明為FactoryBean類型,當提取bean時提取的不是FactoryBean,而是FactoryBean中對應的getObject方法返回的bean,doGetObjectFromFactoryBean就是實現這個功能的。這里factory.getObject()得到的結果並沒有直接返回,而是接下來做了一些后續的操作:AbstraceAutowireCapableBeanFacotory類的postProcessObjectFromFactoryBean方法:
--> AbstraceAutowireCapableBeanFacotory.postProcessObjectFromFactoryBean
--> applyBeanPostProcessorsAfterInitialization(object, beanName)
applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
我們需要保證,盡可能保證所有的bean初始化后都會調用注冊的BeanPostProcessor的postProcessAfterInitialization方法進行處理,在實際開發中大可以針對此特性設計自己的業務邏輯。

4 獲取單例
前面說的從緩存中加載單例的過程,對於緩存中沒有單例,需要從頭加載bean。
getSingleton(String beanName, ObjectFactory singletonFactory)
這里使用了回調使在創建在后做一些操作,而真正創建在ObjectFactory類型的實例singletonFactory.getObject()中實現。這個方法的准備操作如下:
(1)檢查緩存是否一斤加載過
(2)如果沒有加載,記錄beanName的正在加載狀態
(3)加載單例前記錄加載狀態 beforeSingletonCreation(beanName)
看着沒有操作,其實是記錄加載狀態,也就是通過this.singletonCurrentlyInCreation.add(beanName)加入緩存,可以對循環依賴進行檢測
(4)通過調用參數傳入的ObjectFactory的個體Object方法實例化bean
(5)加載單例后的處理方法調用。和步驟(3)一樣,記錄加載狀態
(6)將結果記錄至緩存並刪除加載bean過程中所記錄的各種輔助狀態
(7)返回處理結果
到這里,還是沒加載bean,bean的加載過程是在傳入的ObjectFactory類型的參數singletonFactory中定義的,核心部分其實只是調用了createBean的方法

5 准備創建 bean
--> createBean(final String beanName, final RootBeanDefinition mbd, final Oject[] args)
1 根據設置的class屬性或者根據className解析class
2 對override屬性進行標記及驗證
mbd.prepareMethodOverrides()
3 應用初始化的后處理器,解析置頂bean是否存在初始化前的短路操作
resolveBeforeInstantiation(beanName, mbd)
4 創建bean
doCreateBean(beanName, mbd, args)

2_處理override屬性 prepareMethodOverrides()
spring中沒有override-method這樣的配置,但是有looup-method和replace-method。而這兩個配置的加載其實就是將配置統一存放在BeanDefinition中的methodOverrides屬性里,這兩個功能實現原理其實是在bean實例化的時候如果檢測到存在methodOverrides屬性,會動態的為當前bean生成代理,並使用對應的攔截器為bean做增強處理。

3_ 實例化的前置處理
在真正調用doCreateBean前調用了這么一個方法resolveBeforeInstantiation(beanName, mbd)對BeanDefiniton中的屬性做些前置處理。
(1)實例化前的后處理器應用 resolveBeforeInstantiation(beanName, mbd) --> applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName)
(2)實例化后的后處理器應用 resolveBeforeInstantiation(beanName, mbd) --> applyBeanPostProcessorsAfterInstantiation(Object existingBean, String beanName)

6 循環依賴 (上網搜一下)
對於“prototype”作用域bean,spring無法依賴注入,因為spring容易不進行緩存“prototype”作用域的bean,因此無法提前暴露一個創建中的bean。對於“singleton”作用域的bean,可以通過“setAllowCircularReferences(false)”來禁止魂環引用

7 創建bean
當經歷過resolveBeforeInstantiation方法后,程序有兩個選擇,如果創建了代理獲取說重寫了InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法並在方法postProcessBeforeInstantiation中改變了bean,則直接返回就可以了,否則需要進行常規bean的創建。常規的bean的創建是在doCreateBean中完成的
doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
1 如果是單例則需要首先清除緩存
2 實例化bean,將BeanDefinition轉換為BeanWrapper createBeanInstance(beanName, mbd, args)
1 如果存在工廠方法,使用工廠方法進行初始化
2 根據參數鎖定構造器函數進行初始化
3 既不存在工廠方法也不存在有參數的構造器,使用默認構造器進行bean的實例化
3 MergedBeanDefinitionPostProcessor的應用 : Autowired正式通過此方法使用諸如類型的預解析
4 依賴處理 : 如果是單例,通過緩存中的ObjectFactory來穿件實例
5 屬性填充 將所有屬性填充進bean實例中
6 循環依賴檢查 檢測已經加載的bean是否已經出現了依賴循環,並判斷是否需要拋異常
7 注冊DisposableBean 如果配置了destroy-method,這里需要注冊便於在銷毀的時候調用
8 完成創建並返回

2_ createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)
1 如果在RootBeanDefinition中存在factoryMethodName屬性,或者說在配置文件中配置了factory-method,那么會嘗試使用instantiateUsingFactoryMethod(beanName, mbd, args)方法根據RootBeanDefinition中的配置生成bean的實例
2 解析構造函數並進行構造函數的實例化。應為一個bean敵營的類中可能會有多個構造函數,而每個構造函數的參數不同,根據參數判斷用哪個。但判斷過程復雜,因此采用緩存機制,如果已經解析過則直接從RootBeanDefinition中的屬性resolvedConstructorOrFactoryMethod緩存的值去取,否則在去解析,解析后添加至RootBeanDefinition中的屬性resolvedConstructorOrFactoryMethod中。

3_ 記錄創建bean的ObjectFactory
earlySingletonExposure:提早曝光的單例
mbd.inSingleton()是否是單例
this.allowCircularRefences:是否允許循環依賴,沒有配置,只能硬編碼bf.setAlowBeanDefinitionOverriding(false);
isSingletonCurentlyInCreateion(beanName):該bean是否在創建中。spring中會有個專門的屬性默認為DefaultSingletonBeanRegistry的singleTonsCurrentlyInCreation來記錄bean的加載狀態,在bean開始創建前會將beanName記錄在屬性中,在bean創建結束后從屬性移除。不同的scope記錄位置不一樣,singleton記錄屬性的函數在DefaultSingletonBeanRegistry類的getSingleton(String beanName, ObjectFactory singletonFactory)函數的beforeSingletonCreateion(beanName)和afterSingletonCreateion(beanName)中,分別對應this.singletonCurrentlyInCreateion.add(beanName),this.singletonCurrentlyInCreateion.remove(beanName)

========================================================================
依賴循環:
A中有B,B中有A
創建beanA -- 開始創建bean(記錄beanName) -- addSingletonFactory -- populateBean(屬性填充) -- 結束創建bean(異常beanNameA)
在屬性填充時,涉及到beanB的創建,既重復上面的步驟,在B屬性填充時,通過ObjectFactory提供的實例化方法來終端A中屬性的填充,使B中持有A僅僅是剛剛初始化並沒有填充任何屬性的A,而真正初始化A的步驟還是在最開始創建A的時候進行的,但是因為A與B中的A所表示的屬性地址是一樣的,所以在A中創建好的屬性填充自然可以通過B中的A獲取,這樣就解決了循環依賴的問題。
=========================================================================

4_ 屬性填充
1 InstantiationAwareBeanPostProcessor處理器的postProcessAfterInstantiation函數的應用,此函數可以控制程序是否繼續進行屬性填充
2 根據注入類型(byName/byType),提取依賴的bean,並統一存入PropertyValues中
3 應用InstantiationAwareBeanPostProcessor處理器的postProcessPropertyValues方法,對屬性獲取完畢填充前對屬性的再次處理,典型應用是RequiredAnnotationBeanPostProcessor類中對屬性的驗證
4 建所有PropertyValues中的屬性填充至BeanWrapper中

1__ 我自己的理解:還是拿上面A、B的例子,在A填充屬性B的時候,進入B的創建、填充,在B中填充屬性A的時候,走進代碼ibp.postProcessPropertyValues(bw.getWrappedInstantce(), beanName)時,此時的判斷在這里為false,走進break,循環終止,停止填充,此時A的狀態是最原始的狀態,但是B中已經有了A,B填充完畢,在走進A填充的代碼,A中此時有了B,判斷條件為true,不進break代碼,繼續進行A的填充,A是單例的B中最終的A也是屬性填充完畢的。至此,填充完畢。byName注入時調用getBean(propertyName),注冊依賴registerDependentBean(propertyName, beanName)時,第二章有,先獲取bean,沒有在獲取bean的ObjectFactory,在通過ObjectFactory獲取bean,判斷ObjectFactory中是否有A的工廠方法。第一次進入A的填充時沒有,B填充A的時候,就已經有了,因此判斷條件不一樣。

7_ 初始化bean bean中有一個init-method屬性
initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)
1__ 激活Aware方法
spring提供一些Aware接口:BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware。實現這些Aware接口的bean在實例化后,可以獲取一些相對應的資源,例如實現BeanFactoryAware的bean,在bean被初始化后,將被注入ApplicationContext的實例等。

2__ 處理器的應用
spring除了BeanPostProcessor外還有很多PostPorcessor,集成自BeanPostProcessor。在調用客戶自定義的初始化方法前以及調用自定義初始化方法后分別會調用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,使用戶可以根據自己的業務需求進行響應的處理。

2_ 激活自定義的init方法
除了使用init-method外,還有使自定義的bean實現InitializingBean接口,並在afterPropertiesSet中實現自己的初始化業務邏輯。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM