Spring-5.1.5源碼解析【IOC】(二)

在上一篇博客內(nèi)容中,我們已經(jīng)看了解析 import.alias的源碼了,接下來(lái)就是bean的這塊了:

processBeanDefinition(ele, delegate):

從第一個(gè)方法開(kāi)始看過(guò)來(lái),parseBeanDefinitionElement的具體實(shí)現(xiàn):

圖沒(méi)有截全,不過(guò)沒(méi)關(guān)系滋迈,我們先看這部分,分開(kāi)來(lái)看

1.先獲取id與name屬性户誓,將name按照分隔符切割為數(shù)組饼灿,因?yàn)槲覀僴ame可以用逗號(hào)分隔來(lái)指示多個(gè)別名,然后將這個(gè)數(shù)組添加進(jìn)一個(gè)新創(chuàng)建的集合中帝美,如果id屬性為空的話碍彭,創(chuàng)建的name集合又不為空,那么將以第一個(gè)name為這個(gè)bean的id

2.checkNameUniqueness(beanName.aloases,ele):該方法的目的是校驗(yàn)這個(gè)id悼潭,是否存在所有的bean的id集合中庇忌,該集合為一個(gè)Set集合,因?yàn)橐WCid的強(qiáng)一致性(即使A bean的id 與B bean 的name有相同也是不行的舰褪,因?yàn)閎ean的name屬性也會(huì)被添加進(jìn)這個(gè)集合中皆疹,如果有定義了多個(gè)name,那么第一個(gè)值占拍,必須是唯一的略就,如果在name的數(shù)組中還找到了相同的,同樣會(huì)提示Error)

接著上圖往下看:

AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean):?解析bean定義本身晃酒,而不考慮名稱或別名

AbstractBeanDefinition :具體的BeanDefinition類的基類表牢,分解出GenericBeanDefinition,RootBeanDefinition和ChildBeanDefinition的公共屬性

以這里為這個(gè)方法的第一步看

this.parseState =?ParseState對(duì)象

ParseState:基于簡(jiǎn)單LinkedList的結(jié)構(gòu),用于跟蹤解析過(guò)程中的邏輯位置

Entry:在解析階段的每一點(diǎn)都以特定于讀取器的方式添加到LinkedList中贝次。用于ParseState條目的標(biāo)記接口

BeanEntry:表示bean定義的ParseState條目

之后經(jīng)量講明白崔兴,盡量少截點(diǎn)圖,哈哈哈

接下來(lái)來(lái)看第二部分:

bd.setResource(this.readerContext.getResource());

bd.setSource(extractSource(ele));

return bd;? ?(這里是補(bǔ)充)

這里我們來(lái)詳細(xì)看下怎么設(shè)置property屬性的吧,其他的地方都比較簡(jiǎn)單敲茄,property屬性我們也使用的最多了螺戳,所以看下實(shí)現(xiàn)原理也是有必要滴

parsePropertyElements(ele, bd):

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {

????????NodeList nl = beanEle.getChildNodes();

????????for (int i = 0; i < nl.getLength(); i++) {

????????????????????Node node = nl.item(i);

????????????????????if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { //property

????????????????????????????parsePropertyElement((Element) node, bd);

????????????????????}

????????}

}

如果是property標(biāo)簽則進(jìn)入parsePropertyElement方法:

public void parsePropertyElement(Element ele, BeanDefinition bd) {

? ? ? ? ? ?String propertyName = ele.getAttribute(NAME_ATTRIBUTE); // name

? ? ? ? ? ?if (!StringUtils.hasLength(propertyName)) {

????????????????????error("Tag 'property' must have a 'name' attribute", ele);

????????????????????return;

????????????}

? ? ? ? ? ? // 添加propertyName條目

????????????this.parseState.push(new PropertyEntry(propertyName));

????????????try {

????????????????????????//校驗(yàn)該peoperty是否已存在

????????????????????????if (bd.getPropertyValues().contains(propertyName)) {

????????????????????????????????error("Multiple 'property' definitions for property '" + propertyName + "'", ele);

????????????????????????????????return;

????????????????????????}

? ? ? ? ? ? ? ? ? ? ? ? //?獲取屬性元素的值 (具體怎么做的在下面可以看得到)

????????????????????????Object val = parsePropertyValue(ele, bd, propertyName);

? ? ? ? ? ? ? ? ? ? ? ?// 屬性值對(duì)象?

????????????????????????PropertyValue pv = new PropertyValue(propertyName, val);

? ? ? ? ? ? ? ? ? ? ? ?// 判斷是否存在meta標(biāo)簽,有則設(shè)置進(jìn)pv中折汞,因?yàn)槲覀冊(cè)趯懪渲梦募臅r(shí)候其實(shí)是可以往property標(biāo)簽中插入meta標(biāo)簽的

????????????????????????parseMetaElements(ele, pv);

? ? ? ? ? ? ? ? ? ? ? ? // 這里啥也沒(méi)干

????????????????????????pv.setSource(extractSource(ele));

? ? ? ? ? ? ? ? ? ? ? ? // 添加進(jìn)BeanDefinition中

????????????????????????bd.getPropertyValues().addPropertyValue(pv);

????????????} finally {

? ? ? ? ? ? ? ? ? ? ? ? // 這里就不用說(shuō)了,要不然就顯得太羅嗦了

????????????????????????this.parseState.pop();

????????????}

}


Object val = parsePropertyValue(ele, bd, propertyName):獲取屬性值

1.首先是property的子元素是否只有一個(gè)

2.直接貼代碼

boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);? ? ? ? ? ? ? ? ? ? ?//ref

boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);???????????? //value

// ref和value屬性不能一起出現(xiàn)在一個(gè)property標(biāo)簽中

if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) {

????????error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);

}

if (hasRefAttribute) {

????????String refName = ele.getAttribute(REF_ATTRIBUTE);

????????if (!StringUtils.hasText(refName)) {

????????????????error(elementName + " contains empty 'ref' attribute", ele);

????????}

? ? ? ? //?RuntimeBeanReference? :不可變占位符類盖腿,當(dāng)屬性值對(duì)象引用工廠中的另一個(gè)bean時(shí)爽待,用于在運(yùn)行時(shí)解析它

? ? ? ?RuntimeBeanReference ref = new RuntimeBeanReference(refName);

? ? ? ?// 啥也不干?

? ? ? ?ref.setSource(extractSource(ele));

? ? ? ?return ref;

?}else if (hasValueAttribute) {

? ? ? ? //?TypedStringValue:Spring類型字符串值的Holder◆娓可以添加到bean定義中鸟款,以便顯式地指定字符串值的目標(biāo)類型,例如集合元素

? ? ? ? //?這個(gè)holder只存儲(chǔ)字符串值和目標(biāo)類型茂卦。實(shí)際的轉(zhuǎn)換將由bean工廠執(zhí)行何什。

????????TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));

? ? ? ? // 這里也是啥都不干

????????valueHolder.setSource(extractSource(ele));

????????return valueHolder;

}

PropertyValue:對(duì)象來(lái)保存單個(gè)bean屬性的信息和值。在這里使用一個(gè)對(duì)象等龙,而不是僅僅將所有屬性存儲(chǔ)在一個(gè)按屬性名鍵控的映射中处渣, 這允許更大的靈活性,以及以優(yōu)化的方式處理索引屬性等蛛砰。

MutablePropertyValues:PropertyValues接口的默認(rèn)實(shí)現(xiàn),允許對(duì)屬性進(jìn)行簡(jiǎn)單的操作罐栈,并提供構(gòu)造函數(shù)來(lái)支持映射的深度復(fù)制和構(gòu)造。

然后就沒(méi)有然后了泥畅。就直接返回了荠诬,再回到parseBeanDefinitionElement方法中可以發(fā)現(xiàn),下面還有一些對(duì)于bean的id為空的情況下的處理位仁,這里我就不說(shuō)了(時(shí)間原因柑贞,其實(shí)看源碼看到這里,接下來(lái)的東西也就沒(méi)啥難度了)

那么就回到parseBeanDefinitionElement方法的最后這一點(diǎn) :

String[] aliasesArray = StringUtils.toStringArray(aliases);? ? ? ? ? ? ? ?

return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);

BeanDefinitionHolder:包含名稱和別名的bean定義的Holder聂抢【唬可以注冊(cè)為內(nèi)部bean的占位符。注冊(cè)RootBeanDefinition或ChildBeanDefinition就足夠了

最后返回的是BeanDefinitionHolder對(duì)象.

這里習(xí)慣性做個(gè)總結(jié)吧:

1.如果name屬性為空涛浙,別名集合不為空康辑,那么將以第一個(gè)別名設(shè)置為該bean的id

2.驗(yàn)證指定的bean名稱和別名在當(dāng)前bean元素嵌套級(jí)別中尚未使用

3.創(chuàng)建GenericBeanDefinition,并且為 GenericBeanDefinition 設(shè)置parentName轿亮,className

4.設(shè)置前置屬性(singleton疮薇,scope,abstract我注,default-lazy-init按咒,autowire,depend-on,autowire-candidate,primary励七,init-method智袭,destroy-method...)

5.判斷是否有description標(biāo)簽,如果有則返回

6.判斷是否是meta標(biāo)簽,如果存在設(shè)置進(jìn)BeanDefintion

7.判斷是否是lookup-method標(biāo)簽,如果存在則添加進(jìn)覆蓋方法列表

8.判斷是否是replaced-method標(biāo)簽,如果存在則添加進(jìn)替換方法列表

9.解析給定bean元素的構(gòu)造 constructor-arg子元素

10.解析屬性元素

11:解析qualifier元素?????

12:設(shè)置source為XmlBeanDefinitionReader

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

//BeanDefinitionHolder :包含名稱和別名的bean定義的Holder掠抬『鹨埃可以注冊(cè)為內(nèi)部bean的占位符。

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);? ? ? ? ? ? // 這里咱們就看完了两波,接著往下看

????????if (bdHolder != null) {

? ? ? ? ? ? ? ? // 解析我們自定義的屬性

????????????????bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

????????????????try {

????????????????????????// Register the final decorated instance. // 注冊(cè)最后修飾后的實(shí)例瞳步。

????????????????????????BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

? ? ? ? ? ? ? ? } catch (BeanDefinitionStoreException ex) {

????????????????????????getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);

????????????????}

????????????????// Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

????????}

}

???bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder):

public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {

????????BeanDefinitionHolder finalDefinition = definitionHolder;

????????// 首先基于自定義屬性進(jìn)行裝飾

????????NamedNodeMap attributes = ele.getAttributes();

????????for (int i = 0; i < attributes.getLength(); i++) {

????????????????Node node = attributes.item(i);

????????????????finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);

????????}

????????// 基于自定義嵌套元素的裝飾

????????NodeList children = ele.getChildNodes();

????????for (int i = 0; i < children.getLength(); i++) {

????????????????Node node = children.item(i);

????????????????if (node.getNodeType() == Node.ELEMENT_NODE) {

????????????????????????finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);

????????????????}

????????}

????????return finalDefinition;

}


BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()) : 注冊(cè)最后修飾后的實(shí)例,將給定的bean定義注冊(cè)到給定的bean工廠

getReaderContext().getRegistry()? 等同于 XmlBeanDefinitionReader.getRegistry() 返回DefaultListableBeanFactory

public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {

????????// Register bean definition under primary name.

????????String beanName = definitionHolder.getBeanName();

????????registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());? ? ? ? ? ? ? ? // 我們主要來(lái)看看這個(gè)方法是怎么實(shí)現(xiàn)的

????????// Register aliases for bean name, if any.

????????String[] aliases = definitionHolder.getAliases();

????????if (aliases != null) {

????????????????for (String alias : aliases){

????????????????????registry.registerAlias(beanName, alias);

????????????????}

????????}

}

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()):

這種太長(zhǎng)的方法腰奋,我就還是直接貼圖把单起,要不然整理格式都得好久

1.首先是對(duì)beanDefinition進(jìn)行校驗(yàn)(存在覆蓋方法并且工廠方法不為空(創(chuàng)建該Bean的工廠方法就不能被覆蓋,校驗(yàn)該beanClass是否為Class實(shí)例)

2.然后在BeanDefinition緩存中找,目的是為了知道該beanName的beanDefinition是否已經(jīng)存在劣坊,如果存在做另外一種處理嘀倒,這里我們就不看了

3.判斷該beanName是否已經(jīng)創(chuàng)建過(guò)(AbstractBeanFactory中的alreadyCreated:至少創(chuàng)建過(guò)一次的bean的名稱),如果不為空的話局冰,首先是先把咱們的beanName與BeanDefinition添加進(jìn) beanName -> BeanDefinition的緩存中测蘑,然后從新初始化bean定義名稱列表(beanDefinitionNames集合,也是DefaultListableBeanFactory中的屬性康二,一個(gè)List集合)帮寻,初始化的目的就是為了將我們的beanName添加進(jìn)集合中,接著如果beanName存在與手動(dòng)注冊(cè)的單例程序的名稱列表(DefaultListableBeanFactoty中的屬性赠摇,一個(gè)Set集合)中的話固逗,也是從新初始化該集合,不同的是這里是從集合中刪除該beanName(如果是存在集合中的話), 初始化(copy-on-write)

4.那就是第三步的else部分了藕帜,這里比第三步就直接多了烫罩,beanName與BeanDefinition添加進(jìn) beanName -> BeanDefinition的緩存中,beanName添加進(jìn)bean定義名稱列表洽故,刪除手動(dòng)注冊(cè)的單例程序的名稱列表中的該beanName

5.最后一步贝攒,判斷beanDefintion是否存在或者是否已經(jīng)存在與我們的緩存映射中,如果滿足條件則開(kāi)始清理时甚,我們來(lái)把清理的過(guò)程和內(nèi)容記錄一下

1.緩存對(duì)象的bean的名字:bean名稱到bean實(shí)例中刪除beanName???????????????????????????????DefaultSingletonBeanRegistry.singletonObjects

2.單例工廠的緩存:對(duì)象工廠的bean名稱中刪除beanName???????????????????????????????????????????DefaultSingletonBeanRegistry.singletonFactories??????

3.早期:?jiǎn)卫龑?duì)象緩存的bean bean實(shí)例的名字中刪除beanName? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DefaultSingletonBeanRegistry.earlySingletonObjects? ??

4.注冊(cè)的單例集合隘弊,按注冊(cè)順序包含bean名稱中刪除beanName????????????????????????????????????DefaultSingletonBeanRegistry.registeredSingletons

5.手動(dòng)注冊(cè)的單例程序的名稱列表,按注冊(cè)順序排列(再特么刪一次)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DefaultListableBeanFactory.manualSingletonNames

6.清空單例和非單例bean名稱的映射荒适,按依賴項(xiàng)類型鍵控? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DefaultListableBeanFactory.allBeanNamesByType? ? ? ? ?

7.清空單一bean名稱的映射梨熙,按依賴項(xiàng)類型鍵控? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??DefaultListableBeanFactory.singletonBeanNamesByType

到這里registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())就已經(jīng)結(jié)束了,這一步的話其實(shí)主要就是將beanName與創(chuàng)建好的BeanDefinition放在緩存中管理起來(lái)刀诬,回到registerBeanDefinition方法中我們繼續(xù)往下看

//? ?為bean名稱注冊(cè)別名(如果有的話)?

String[] aliases = definitionHolder.getAliases();

if (aliases != null) {

? ??for (String alias : aliases) {

? ??????registry.registerAlias(beanName, alias);

? ? }

}

registry.registerAlias(beanName, alias): 這個(gè)地方我就直接把代碼貼上這樣方便看咽扇,內(nèi)容也挺簡(jiǎn)單的,所以就不記錄下來(lái)了

public void registerAlias(String name, String alias) {

????????Assert.hasText(name, "'name' must not be empty");

????????Assert.hasText(alias, "'alias' must not be empty");

? ??????synchronized (this.aliasMap) {

? ??????????????if (alias.equals(name)) {

? ??????????????????????this.aliasMap.remove(alias);

? ??????????????????????if (logger.isDebugEnabled()) {

? ??????????????????????????????????logger.debug("Alias definition '" + alias + "' ignored since it points to same name");

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ?}else{

? ? ? ? ? ? ? ? ? ? ? ??String registeredName = this.aliasMap.get(alias);

? ??????????????????????if (registeredName != null) {

? ??????????????????????????????if (registeredName.equals(name)) {

? ??????????????????????????????????????return;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ??????????????????????????????if (!allowAliasOverriding()) { // 是否允許別名覆蓋。默認(rèn)值是true;

? ??????????????????????????????????????throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for ????????????????????????????????????????name '" + registeredName + "'.");

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ??????????????????????????????if (logger.isDebugEnabled()) {

? ??????????????????????????????????????logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name ????????????????????????????????????????????'" + name + "'");

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? }

? ??????????????????????checkForAliasCircle(name, alias); // 檢查給定名稱是否已經(jīng)指向另一個(gè)方向的給定別名作為別名

? ??????????????????????this.aliasMap.put(alias, name); // 添加進(jìn)id與alias的映射

? ??????????????????????if (logger.isTraceEnabled()) {

? ??????????????????????????????logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");

? ? ? ? ? ? ? ? ? ? ? ? }

????????????????}

? ? ? ? }

}

ok了质欲,BeanDefintion跟Aliases都注冊(cè)了树埠,那么registerBeanDefinition這個(gè)方法就完了,就是這樣啦嘶伟,哈哈哈哈怎憋,不管里頭有多復(fù)雜,反正就是特么的兩件事九昧,注冊(cè)我們根據(jù)<bean> 創(chuàng)建的BeanDefintion,注冊(cè)該Bean的別名

那我們?cè)倩氐絧rocessBeanDefinition方法中盛霎,還有最后一個(gè)方法:,其實(shí)最后這個(gè)地方都可以不用說(shuō)了,因?yàn)檫@里其實(shí)也還是啥都沒(méi)干(反正調(diào)ReaderContext中那三個(gè)屬性的方法都是沒(méi)干活的耽装,哈哈哈哈哈)

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))?

是吧,哈哈哈哈

那這里就完了.....就沒(méi)了期揪,真的沒(méi)了掉奄,然后我們?cè)倩氐阶畛醯膁oRegisterBeanDefinitions方法中,我們?cè)倏纯磒arseBeanDefinitions(root, this.delegate);下面還有沒(méi)有其他的方法需要進(jìn)去看看

parseBeanDefinitions(root, this.delegate);? ? ? ? ? ? ? ? //這個(gè)已經(jīng)看完了

postProcessXml(root);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 這里不用看凤薛,因?yàn)橄旅娴膶?shí)現(xiàn)是空的

this.delegate = parent;

this.delegate = parent: 這里我想我大概弄懂為啥要這樣子再賦值一下的意義了姓建,在進(jìn)入方法的第一步時(shí)就把這個(gè)delegate 賦值給了parent對(duì)象,最后再賦值回來(lái)缤苫,這說(shuō)明它想保存當(dāng)時(shí)的狀態(tài)速兔,但是為啥要這樣子搞,我還不清楚

回到parseDefaultElement方法中活玲,目前我們已經(jīng)把解析import涣狗,alias,bean都說(shuō)了舒憾,還有最后一個(gè)

else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)){

????// 檢查節(jié)點(diǎn)名稱是否等于beans // recurse

????doRegisterBeanDefinitions(ele);

}

這就不用看了镀钓,因?yàn)檫€不是回著頭再搞一次,我們本來(lái)就是通過(guò)doRegisterBeanDefinitions方法進(jìn)入的嘛 ==



接著再回到AbstractRefreshableApplicationContext:

好了镀迂,這里終于看完了

再回到這個(gè)最初的方法:

這個(gè)地方那就是返回我們上面創(chuàng)建的DefaultListableBeanFactory了?

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 到這里這個(gè)方法就算是結(jié)束了,做個(gè)總結(jié):

1.new??DefaultListableBeanFactory,AbstractBeanFactory中設(shè)置parentBeanFactory為ApplicationContext,factoryBean設(shè)置唯一標(biāo)識(shí)

2.對(duì)ioc容器進(jìn)行定制化丁溅,如設(shè)置啟動(dòng)參數(shù),開(kāi)啟注解的自動(dòng)裝配等

3.解析<bean>并且注冊(cè)BeanDefinition

4.AbstractAutowireCapableBeanFactory的忽略依賴關(guān)系接口集合屬性中添加了 BeanNameAware,BeanFactoryAware探遵,BeanClassLoaderAware

5.AbstractBeanDefinitionReader中設(shè)置resourceLoader 為PathMatchingResourcePatternResolver

6.AbstractBeanDefinitionReader中設(shè)置environment 為StandardEnvironment

7.設(shè)置XmlBeanDefinitionReader的Environment屬性為AbstractApplicationContext中的StandardEnvironment (在我們之前super(parent)這一步的時(shí)候給new的)

8.設(shè)置XmlBeanDefinitionReader的ResourceLoader為AbstractXmlApplicationContext

9.設(shè)置XmlBeanDefinitionReader的EntityResolver為ResourceEntityResolver

10.設(shè)置AbstractRefreshableApplicationContext的beanFactory屬性為DefaultListableBeanFactory

11.返回DefaultListableBeanFactory


3.prepareBeanFactory(beanFactory):

一個(gè)一個(gè)來(lái)窟赏,先從第一個(gè)開(kāi)始

這里我們應(yīng)該是沒(méi)有給DefaultResourcceLoader設(shè)置過(guò)屬性的(反正我印象中是沒(méi)有 ==),那我們就直接看ClassUtils.getDefaultClassLoader()這個(gè)方法吧

這個(gè)方法很簡(jiǎn)單吧箱季,先記起來(lái)這里是從當(dāng)前線程中獲取classLoader

? ?下一步 :beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

先來(lái)說(shuō)說(shuō)這兩個(gè)類是啥類:

StandardBeanExpressionResolver:BeanExpressionResolver?接口的標(biāo)準(zhǔn)實(shí)現(xiàn)涯穷,?使用Spring的表達(dá)式模塊解析和評(píng)估Spring EL

SpelParserConfiguration :?SpEL表達(dá)式解析器的配置對(duì)象

SpelExpressionParser :?SpEL 分析器。實(shí)例是可重用和線程安全的藏雏。

其實(shí)這種我們?cè)谥暗牟襟E中也有類似的求豫,只不過(guò)在處理這塊沒(méi)這么高大上而已,哈哈哈哈,這里我就不細(xì)說(shuō)是哪個(gè)地方了蝠嘉,大家可以自己再?gòu)念^對(duì)著源碼看一遍? >_<

我們來(lái)寫個(gè)Demo看看這到底是干嘛的吧最疆,光說(shuō)的話太不清晰了

有意思的事情就這么發(fā)生了

這個(gè)可能還不怎么明顯,我們?cè)賮?lái)一種玩法

注意配置文件給換了哦~

我再把這個(gè)User類給貼上就知道啥意思了 ==?

這下子清晰了吧 == !

我就不介紹太多了蚤告,給大家推薦兩個(gè)地址吧努酸,哈哈哈

http://www.cnblogs.com/longronglang/p/6180023.html? ? ??

https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/expressions.html

下一個(gè):

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));? ?//屬性編輯器

自定義屬性編輯器或注冊(cè)表以應(yīng)用于此工廠的bean。

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)):

ApplicationContextAwareProcessor:該類是BeanPostProcessor接口的實(shí)現(xiàn)它是用來(lái)處理和回調(diào)Aware接口的Bean杜恰,不知道大家有沒(méi)有這樣子使用過(guò):

寫一個(gè)接口繼承ApplicationContextAware接口获诈,重寫setApplicationContext方法,然后某個(gè)實(shí)現(xiàn)類心褐,就可以獲取到ApplicationContext對(duì)象舔涎,具體怎么玩,我們還是來(lái)寫個(gè)Demo吧

寫個(gè)測(cè)試接口繼承ApplicationContextAware接口

吶~就是這樣了

我們來(lái)看看這個(gè)方法里頭是怎么做的:

考慮到安全問(wèn)題逗爹,所以直接是使用CopyOnWriteArrayList這個(gè)對(duì)象 (不得不說(shuō)看Spring源碼亡嫌,真的是學(xué)到了很多東西)

CopyOnWriteArrayList這個(gè)類的介紹給大家推薦一個(gè)很不錯(cuò)的地方去看:http://ifeve.com/java-copy-on-write/

1.首先是從集合中刪除掉這個(gè)對(duì)象,這里要說(shuō)一點(diǎn)注意的就是后置處理器是按照注冊(cè)的順序提交的掘而,所以添加的這個(gè)元素得是唯一的

2.判斷是否是InstantiationAwareBeanPostProcessor接口的實(shí)例(InstantiationAwareBeanPostPressor接口可以返回代理對(duì)象挟冠,例如在創(chuàng)建Bean時(shí),并不都是通過(guò)反射來(lái)為我們的bean來(lái)直接new一個(gè)對(duì)象的袍睡,很多時(shí)候都是通過(guò)cglib來(lái)生成一個(gè)代理類知染,這樣做的好處就是更方便Spring來(lái)管理這些Bean,例如在Aop的時(shí)候斑胜,代理類就發(fā)揮了很大的作用控淡,這里我們先不細(xì)講,到后面自然就明白了),我們?cè)谶@里穿的是一個(gè)ApplicationContextAwareProcessor對(duì)象止潘,所以這里不管

3.判斷是否是DestructionAwareBeanPostProcessor接口的實(shí)例逸寓,這里也不管,因?yàn)檫@里也是走false(eanPostProcessor的子接口覆山,它添加了一個(gè)before-destruction回調(diào),銷毀bean后置處理器)

4.最后把穿入的beanPostProcessor添加進(jìn)后置處理器集合中竹伸。

來(lái)簡(jiǎn)單看看這個(gè)BeanPostProcessor接口吧,看看實(shí)現(xiàn)它的作用在哪里.

BeanPostProcessor :

ApplicationContext會(huì)自動(dòng)找到我們實(shí)現(xiàn)了BeanPostProcessor接口的所有類簇宽,然后把這些類都注冊(cè)為后置處理器

先貼一張圖 == (我寫的這篇可能圖片勋篓,代碼貼的比較多,可能不符合很多人的閱讀習(xí)慣魏割,這里先說(shuō)聲不好意思了譬嚣,因?yàn)槲矣X(jué)得貼圖比較親切 ==。)

直接來(lái)寫個(gè)Demo看看這個(gè)實(shí)現(xiàn)了這個(gè)接口到底能干嘛吧 ==?

這里我可是給user設(shè)置了name的

這里我可沒(méi)有設(shè)置喲? =_=

吶钞它,就是這樣

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);

beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);

beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);

beanFactory.ignoreDependencyInterface(MessageSourceAware.class);

beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

這里大家應(yīng)該不陌生拜银,因?yàn)樵诳磑btainFreshBeanFactory()該方法的源碼時(shí)殊鞭,也做過(guò)這種事情 == ,就是往AbstractAutowireCapableBeanFactory中的ignoreDependencyInterfaces Set集合中添加忽略依賴關(guān)系類型

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);

beanFactory.registerResolvableDependency(ResourceLoader.class, this):

beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this):

beanFactory.registerResolvableDependency(ApplicationContext.class, this):

注冊(cè)具有相應(yīng)自動(dòng)獲取值的特殊依賴項(xiàng)類型,添加進(jìn)Default'List'ableBeanFactory的resolvableDependencies集合中

先記下這里是干了這件事

來(lái)看看DefaultListableBeanFactory的體系吧

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)):

檢測(cè)實(shí)現(xiàn)ApplicationListener接口的bean

接著往下:

老規(guī)矩一個(gè)方法一個(gè)個(gè)來(lái)

先從transformedBeanName(name);這個(gè)方法開(kāi)始

判斷我們傳遞的name是不是以“&”開(kāi)頭的尼桶,要是的需要去掉再返回 操灿,另外我們?cè)谂渲肂ean時(shí),我們是可以配置這個(gè)bean的name屬性的也就是這個(gè)Bean的別名泵督,在canonicalName方法中趾盐,我么就是通過(guò)別名來(lái)找到這個(gè)bean的ID,下面就會(huì)說(shuō)到為啥要獲取到Bean 的ID

if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {

return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));

}

1.首先是在DefaultSingletonBeanRegistry中判斷該name是否存在singletonObjects Map屬性中(singletonObjects: 緩存對(duì)象的bean的名字:bean名稱到bean實(shí)例)

2.containsBeanDefinition該方法是一個(gè)抽象方法小腊,在子類DefaultListableBeanFactory中可以找到該方法實(shí)現(xiàn)救鲤,該判斷是判斷在DefaultListableBeanFactory的be'an'DefinitionMap屬性中是否存在(beanDefinitionMap: beanName與BeanDefinition對(duì)象的映射)

BeanFactory parentBeanFactory = getParentBeanFactory();

return (parentBeanFactory !=null && parentBeanFactory.containsBean(originalBeanName(name)));

我們?cè)诳磑btainFreshBeanFactory()方法的源碼時(shí),在實(shí)現(xiàn)中已經(jīng)給AbstractBeanFactory的parentBeanFactory屬性設(shè)置了值秩冈,而這個(gè)值就是一開(kāi)始我們傳入的ApplicationContext,但是ApplicationContext并沒(méi)有賦值本缠,所以它依然還是null,那么這個(gè)方法的返回就是false

總結(jié):?beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME) :?檢測(cè) loadTimeWeaver是否存在bean實(shí)例或BeanDefinition對(duì)象

下一個(gè):

if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {

????????beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());

}

transformedBeanName這個(gè)方法上面已經(jīng)說(shuō)了入问,就不重復(fù)了丹锹,就直接看看下面是干嘛的吧

(containsSingleton(beanName) || containsBeanDefinition(beanName)) &&

(!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName))

這里也是直接走的false因?yàn)槌跏蓟瘯r(shí)這個(gè)bean是既沒(méi)有實(shí)例也沒(méi)有BeanDefinition的,所以這里我們就快速走完吧队他,其他的也不細(xì)講了,等源碼看到一定程度后峻村,再回過(guò)頭來(lái)把這些看一下寫一下麸折,效果可能會(huì)更好一點(diǎn)(其實(shí)我壓根沒(méi)看過(guò)這里的代碼),既然上面已經(jīng)走完了粘昨,但是我們?cè)跅l件里取反垢啼,所以來(lái)看看如果不存在的情況下是對(duì)這個(gè)Bean做了什么處理吧

beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());

直接貼實(shí)現(xiàn),哈哈哈哈张肾,我越來(lái)越愛(ài)直接貼了

這里顯示判斷是否存在該bean 的實(shí)例芭析,不存在則添加,存在則報(bào)錯(cuò)吞瞪,單例嘛

那我們?cè)賮?lái)看看這個(gè)添加的方法

1.該bean添加實(shí)例

2. 刪除該Bean對(duì)應(yīng)的對(duì)象工廠

3.刪除該Bean的早期單例對(duì)象

4.添加進(jìn)注冊(cè)的Bean集合

這里我們來(lái)看看假如這里不是空的會(huì)發(fā)生什么:

synchronized (this.beanDefinitionMap) {

if (!this.beanDefinitionMap.containsKey(beanName)) {

? ? ? ?Set updatedSingletons =new LinkedHashSet<>(this.manualSingletonNames.size() +1);? ?

? ? ? updatedSingletons.addAll(this.manualSingletonNames);

? ? ? updatedSingletons.add(beanName);

? ? ? this.manualSingletonNames = updatedSingletons;

? }

}else {

? ?if (!this.beanDefinitionMap.containsKey(beanName)) {

????????????this.manualSingletonNames.add(beanName);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 手動(dòng)注冊(cè)的單例程序的名稱列表

? ? ?}

}

最后還有一個(gè)clearByTypeCache()

getEnvironment()這個(gè)就不用說(shuō)了吧馁启,不用想也知道這是什么飛機(jī),我們最開(kāi)始就new了一個(gè)StandardEnvironment == 芍秆,下面兩個(gè)也不說(shuō)了惯疙,其實(shí)都一樣了(夜深了,該睡了 == )

到這里prepareBeanFactory方法就算是完了妖啥,我們來(lái)總結(jié)一下吧:

1.從當(dāng)前Thread中獲取類加載器并且設(shè)置進(jìn)beanFactory

2.設(shè)置表達(dá)式的解析策略

3.設(shè)置屬性編輯器

4.設(shè)置后置處理器

5.添加忽略自動(dòng)連接的給定依賴接口

6.從依賴項(xiàng)類型映射到相應(yīng)的對(duì)象

????????????BeanFactory -> DefaultListableBeanFactory

????????????ResourceLoader -> AbstractApplicationContext

????????????ApplicationEventPublisher -> AbstractApplicationContext

????????????ApplicationContext -> AbstractApplicationContext

7.檢測(cè)實(shí)現(xiàn)ApplicationListener接口的bean

8.檢測(cè) loadTimeWeaver是否存在bean實(shí)例或BeanDefinition對(duì)象? ??

9.檢測(cè)是否存在 environment/systemProperties/systemEnvironment??的Bean實(shí)例與BeanDefinition對(duì)象,不存在則添加

還有這么多沒(méi)寫 == 臥槽

感覺(jué)已經(jīng)寫的很多很羅嗦了霉颠,還是不要都寫一塊比較好,不過(guò)我會(huì)盡快把剩下的寫完的荆虱,哈哈哈哈蒿偎,感謝大家的閱覽朽们!(不早了朦蕴,該睡了躏结,明天還得上班呢嘉裤,晚安)

包含名稱和別名的bean定義的Holder茬底∏澹可以注冊(cè)為內(nèi)部bean的占位符马昨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末把曼,一起剝皮案震驚了整個(gè)濱河市胡岔,隨后出現(xiàn)的幾起案子椿息,更是在濱河造成了極大的恐慌歹袁,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寝优,死亡現(xiàn)場(chǎng)離奇詭異条舔,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)乏矾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門孟抗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人钻心,你說(shuō)我怎么就攤上這事凄硼。” “怎么了捷沸?”我有些...
    開(kāi)封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵摊沉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我痒给,道長(zhǎng)说墨,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任苍柏,我火速辦了婚禮尼斧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘试吁。我一直安慰自己棺棵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布熄捍。 她就那樣靜靜地躺著律秃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪治唤。 梳的紋絲不亂的頭發(fā)上棒动,一...
    開(kāi)封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音宾添,去河邊找鬼船惨。 笑死柜裸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的粱锐。 我是一名探鬼主播疙挺,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼怜浅!你這毒婦竟也來(lái)了铐然?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤恶座,失蹤者是張志新(化名)和其女友劉穎搀暑,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體跨琳,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡自点,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脉让。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桂敛。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖溅潜,靈堂內(nèi)的尸體忽然破棺而出术唬,到底是詐尸還是另有隱情,我是刑警寧澤滚澜,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布粗仓,位于F島的核電站,受9級(jí)特大地震影響博秫,放射性物質(zhì)發(fā)生泄漏潦牛。R本人自食惡果不足惜眶掌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一挡育、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧朴爬,春花似錦即寒、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至具滴,卻和暖如春凹嘲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背构韵。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工周蹭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留趋艘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓凶朗,卻偏偏與公主長(zhǎng)得像瓷胧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子棚愤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容