10-Spring初級容器初始化:bean標簽的初步解析

開篇
上一節(jié),我們已經(jīng)尋找到了默認標簽解析的入口,也就是方法parseDefaultElement,千辛萬苦總算是到了標簽的解析環(huán)節(jié)了。
這一節(jié),我們就順著方法parseDefaultElement,來看下Spring是如何解析標簽的,主要包括以下幾個部分:
1.從parseDefaultElement方法開始,看下解析bean標簽解析的入口
2.再來看下bean標簽一開始會解析些什么東西,當然這部分也僅僅只是標簽的初步解析
3.最后我們會看到,在解析bean標簽時會創(chuàng)建BeanDefinition來存放標簽解析的信息
bean標簽解析的入口
這一節(jié),我們沿著上一節(jié)分析的位置,繼續(xù)來看下parseBeanDefinitions方法,如下圖:

我們到方法parseDefaultElement中,看下Spring是如何解析默認標簽的:

可以看到,方法parseDefaultElement的結(jié)構(gòu)就變的挺清晰了,我們看下這幾個常量是什么:


可以看到,這些不就是標簽的名稱嗎,比如標簽bean、alias、import、beans。
因為標簽alias和標簽import在實際開發(fā)中現(xiàn)在用的都比較少了,我們的重點還是來分析下最核心的bean標簽的解析,我們直接到processBeanDefinition方法中看下吧:

跟進到方法processBeanDefinition里面看下:

可以看到,果然還是通過我們之前分析的那樣委托BeanDefinitionParserDelegate來幫我們解析。
那BeanDefinitionParserDelegate具體會如何解析默認標簽bean呢?我們再到delegate的parseBeanDefinitionElement方法中看下:

第一步并沒有什么東西,我們繼續(xù)跟進到方法parseBeanDefinitionElement中看下:

光是看一眼方法,我們就知道bean標簽的解析是有多么復雜,但是,這也是值得我們?nèi)シ治龅?,接下來,我們就一步步來分析下bean標簽解析中的各個環(huán)節(jié)。
bean標簽的初步解析
我們先看到方法parseBeanDefinitionElement中的前兩行代碼:

可以看到,首先是獲取bean標簽中的屬性id的值,以及屬性name的值nameAttr,這一點我們應該不會很陌生,一般我們在bean標簽中都會配置屬性id。
接下來,如果name屬性的值nameAttr不為空的話,會通過方法StringUtils.tokenizeToStringArray進行分割:

其中,MULTI_VALUE_ATTRIBUTE_DELIMITERS的值為 ",; ",也就是說在配置屬性name的值時,可以通過“,”或“;”作為分隔符,配置多個name屬性值。
比如name屬性的值為“student,students”,分割后可以得到nameArr數(shù)組為 [“student”,“students”],然后將數(shù)組添加到aliases集合中。
那aliases集合有什么用呢?我們繼續(xù)看下:

可以看到,當id屬性值為空時,就會從aliases集合中調(diào)用方法remove(0) ,來獲取第一個元素作為beanName的值,當然,以上都是bean標簽解析前的一些準備工作。
我們繼續(xù)往后看下:

根據(jù)方法名parseBeanDefinitionElement,我們應該也能猜到,差不多這里就是解析bean標簽的關(guān)鍵方法了。
不得不再吐槽一點的就是,Spring中方法的各種嵌套對于初次研究源碼的人而言,還真的是一個讓人頭皮發(fā)麻的事,但是,既然是研究Spring源碼我們就盡可能耐心點來吧。
接下來,我們再到方法parseBeanDefinitionElement中看下:

可以看到,還是繼續(xù)解析bean標簽中的屬性,分別獲取屬性class的值className,及屬性parent的值parent,然后將這個兩個屬性的值傳入方法createBeanDefinition中,構(gòu)建一個AbstractBeanDefinition類型的對象bd。
BeanDefinition的創(chuàng)建
那在createBeanDefinition方法中到底在干什么呢?我們進去看下:

可以看到,在createBeanDefinition方法中,BeanDefinitionReaderUtils又調(diào)用方法createBeanDefinition進一步處理,繼續(xù)往下看:

可以看到,實際上是創(chuàng)建的BeanDefinition為GenericBeanDefinition,并且將parent和class屬性的值都設(shè)置到GenericBeanDefinition之后并返回。
那GenericBeanDefinition是什么呢?分析到這里,不知道大家還記得我們前面提到過的,一個bean在Spring容器中其實是以BeanDefinition的形式存在的,也就是說我們在xml中的配置的一個bean標簽,在Spring容器中存在的形式就是BeanDefinition。
但是,BeanDefinition只不過是一個接口,我們剛也看到了,Spring在解析bean標簽時會為我們創(chuàng)建一個GenericBeanDefinition出來,用于存放bean標簽解析出來的各種信息,所以,接下來我們有必要來了解下什么是GenericBeanDefinition。
總結(jié)
好了,今天的知識點,我們就講到這里了,我們來總結(jié)一下吧。
我們及時在整體流程圖中記錄一下當前的分析情況:

這一節(jié),我們終于找到了bean標簽解析的核心入口了,而且,通過我們對方法的層層跟進,發(fā)現(xiàn)已經(jīng)開始解析bean標簽中的一些屬性了,比如屬性id、name、class和parent。
同時,我們也看到了Spring會創(chuàng)建BeanDefinition的實現(xiàn)類GenericBeanDefinition,用于存放bean標簽解析結(jié)果。
那GenericBeanDefinition是什么呢?BeanDefinition還有其他哪些實現(xiàn)類呢?不同的BeanDefinition接口實現(xiàn)類之間,又有什么區(qū)別呢?下一節(jié),我們好好來看下BeanDefinition。