天天看點

死磕Spring系列之三,XML解析相關

通過第2章的介紹,應該知道spring如何從xml一步步解析成bd對象并注冊到容器中,這一過程有個概要認識了。

接下來開始詳細分析與xml相關的那些事。

首先看一下使用的xml文檔。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<code>&lt;?</code><code>xmlversion</code><code>=</code><code>"1.0"</code><code>encoding</code><code>=</code><code>"utf-8"</code><code>?&gt;</code>

<code>&lt;</code><code>beansxmlns</code><code>=</code><code>"http://www.springframework.org/schema/beans"</code>

<code>       </code><code>xmlns:xsi</code><code>=</code><code>"http://www.w3.org/2001/xmlschema-instance"</code>

<code>       </code><code>xsi:schemalocation="http://www.springframework.org/schema/beans</code>

<code>              </code><code>http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"&gt;</code>

<code>              </code><code>&lt;</code><code>beanid</code><code>=</code><code>"beijingcard"</code><code>class</code><code>=</code><code>"com.spring.examples.ioc.bean.card"</code>  <code>&gt;</code>

<code>                     </code><code>&lt;</code><code>propertyname</code><code>=</code><code>"cardno"</code><code>value</code><code>=</code><code>"6220-52103-4123-456"</code><code>&gt;&lt;/</code><code>property</code><code>&gt;</code>

<code>                     </code><code>&lt;</code><code>propertyname</code><code>=</code><code>"bank"</code><code>value</code><code>=</code><code>"北京銀行"</code><code>/&gt;</code>

<code>              </code><code>&lt;/</code><code>bean</code><code>&gt;</code>

<code>              </code><code>&lt;</code><code>beanid</code><code>=</code><code>"jianshecard"</code><code>class</code><code>=</code><code>"com.spring.examples.ioc.bean.card"</code><code>&gt;</code>

<code>                     </code><code>&lt;</code><code>propertyname</code><code>=</code><code>"cardno"</code><code>value</code><code>=</code><code>"6227-52103-4123-456"</code><code>&gt;&lt;/</code><code>property</code><code>&gt;</code>

<code>                     </code><code>&lt;</code><code>propertyname</code><code>=</code><code>"bank"</code><code>value</code><code>=</code><code>"建設銀行"</code><code>/&gt;</code>

<code>             </code> 

<code>              </code><code>&lt;</code><code>beanid</code><code>=</code><code>"miyue"</code>  <code>class</code><code>=</code><code>"com.spring.examples.ioc.bean.user"</code><code>primary</code><code>=</code><code>"true"</code>  <code>scope</code><code>=</code><code>"singleton"</code><code>&gt;</code>

<code>                     </code><code>&lt;</code><code>propertyname</code><code>=</code><code>"username"</code><code>value</code><code>=</code><code>"芈月"</code><code>&gt;&lt;/</code><code>property</code><code>&gt;</code>

<code>                     </code><code>&lt;</code><code>propertyname</code><code>=</code><code>"email"</code><code>value</code><code>=</code><code>"[email protected]"</code><code>&gt;&lt;/</code><code>property</code><code>&gt;</code>

<code>                     </code><code>&lt;</code><code>propertyname</code><code>=</code><code>"cardlist"</code><code>&gt;</code>

<code>                            </code><code>&lt;</code><code>list</code><code>&gt;</code>

<code>                                          </code><code>&lt;</code><code>refbean</code><code>=</code><code>"beijingcard"</code><code>/&gt;</code>

<code>                                          </code><code>&lt;</code><code>refbean</code><code>=</code><code>"jianshecard"</code><code>/&gt;</code>

<code>                            </code><code>&lt;/</code><code>list</code><code>&gt;</code>

<code>                     </code><code>&lt;/</code><code>property</code><code>&gt;</code>

<code>&lt;/</code><code>beans</code><code>&gt;</code>

首先需要知道,

xml 指可擴充标記語言.

第一行是 xml 聲明。它定義 xml 的版本 (1.0) 和所使用的編碼 utf-8)。

下一行描述文檔的根元素&lt;beans&gt;,(像在說:“本文檔包含一個多個bean “):

接下來就是子元素&lt;bean&gt;了。具體标簽含義就不說了。

我想說的是文檔頭部的xmlns=".*",  xmlns:xsi=".*",xsi:schemalocation=".*"類似字樣的一坨代碼含義。

這些就是命名空間。

命名空間

a)為什麼要有命名空間?

xml 命名空間提供避免元素命名沖突的方法。

在 xml 中,元素名稱是由開發者定義的,當兩個不同的文檔使用相同的元素名時,就會發生命名沖突。

b)預設的命名空間(default namespaces)

為元素定義預設的命名空間可以讓我們省去在所有的子元素中使用字首的工作。

c)xsi:schemalocation

schemalocation 屬性引用具有目标命名空間的 xml 架構文檔。

xsi:schemalocation屬性的值由一個uri引用對組成,兩個uri之間以空白符分隔。第一個uri是名稱空間的名字,第二個uri給出模式文檔的位置,模式處理器将從這個位置讀取模式文檔,該模式文檔的目标名稱空間必須與第一個uri相比對

xsd (xml schema definition)

xml schema的用途

1.  定義一個xml文檔中都有什麼元素

2.  定義一個xml文檔中都會有什麼屬性

3.  定義某個節點的都有什麼樣的子節點,可以有多少個子節點,子節點出現的順序

4.  定義元素或者屬性的資料類型

5.  定義元素或者屬性的預設值或者固定值

具體文法,就不講了,有興趣的可以搜尋。

dtd(document type definition文檔類型定義)的作用是定義 xml 文檔的合法構模組化塊。

功能和xsd類似。具體使用如下:

&lt;?xml version="1.0" encoding="utf-8"?&gt;  

&lt;!doctype beans public "-//spring//dtd bean//en" " http://www.springframework.org/dtd/spring-beans.dtd "&gt;  

xsd,知道即可,spring2.0中使用xsd驗證。

解析xml需要關注點

1.xml文檔如何轉換為系統資源

2.使用什麼引擎解析

3.解析文檔元素,解析為資料載體對象

<code>   </code><code>public</code> <code>int</code> <code>loadbeandefinitions(resource resource) </code><code>throws</code> <code>beandefinitionstoreexception {</code>

<code>      </code><code>return</code> <code>loadbeandefinitions(</code><code>new</code> <code>encodedresource(resource));</code>

<code>   </code><code>}</code>

 首先看到這方,咱們關注到參數resource,沒錯spring提供resource接口,将xml檔案封裝為資源對象。

死磕Spring系列之三,XML解析相關

上圖是resource類圖。通過resouce接口,可以知道檔案(xml)的名稱,是否制度,内容長度,是否存在.....。

我們非常熟悉的擷取資源的幾種方式,都能找到。

classpathresource:根據類加載擷取

urlresource:url路徑(遠端)擷取

filesystemresource:檔案路徑擷取

大家有興趣可以仔細看一下。getinputstream()方法要重點關注。

簡單說一下 encodedresource,他持有resource接口引用,添加字元集支援。

2.1.準備輸入(org.xml.sax.inputsource)

int org.springframework.beans.factory.xml.xmlbeandefinitionreader.loadbeandefinitions(encodedresource encodedresource) throws beandefinitionstoreexception

26

27

28

29

30

31

32

33

34

35

36

37

38

39

<code> </code><code>public</code> <code>int</code> <code>loadbeandefinitions(encodedresource encodedresource) </code><code>throws</code> <code>beandefinitionstoreexception {</code>

<code>      </code><code>assert.notnull(encodedresource, </code><code>"encodedresource must not be null"</code><code>);</code>

<code>      </code><code>if</code> <code>(logger.isinfoenabled()) {</code>

<code>         </code><code>logger.info(</code><code>"loading xml bean definitions from "</code> <code>+ encodedresource.getresource());</code>

<code>      </code><code>}</code>

<code> </code> 

<code>      </code><code>set&lt;encodedresource&gt; currentresources = </code><code>this</code><code>.resourcescurrentlybeingloaded.get();</code>

<code>      </code><code>if</code> <code>(currentresources == </code><code>null</code><code>) {</code>

<code>         </code><code>currentresources = </code><code>new</code> <code>hashset&lt;encodedresource&gt;(</code><code>4</code><code>);</code>

<code>         </code><code>this</code><code>.resourcescurrentlybeingloaded.set(currentresources);</code>

<code>      </code><code>if</code> <code>(!currentresources.add(encodedresource)) {</code>

<code>         </code><code>thrownew beandefinitionstoreexception(</code>

<code>                </code><code>"detected cyclic loading of "</code> <code>+ encodedresource + </code><code>" - check your import definitions!"</code><code>);</code>

<code>      </code><code>try</code> <code>{</code>

<code>         </code><code>inputstream inputstream = encodedresource.getresource().getinputstream();</code>

<code>         </code><code>try</code> <code>{</code>

<code>            </code><code>inputsource inputsource = </code><code>new</code> <code>inputsource(inputstream);</code>

<code>            </code><code>if</code> <code>(encodedresource.getencoding() != </code><code>null</code><code>) {</code>

<code>                </code><code>inputsource.setencoding(encodedresource.getencoding());</code>

<code>            </code><code>}</code>

<code>            </code><code>return</code> <code>doloadbeandefinitions(inputsource, encodedresource.getresource());</code>

<code>         </code><code>}</code>

<code>         </code><code>finally</code> <code>{</code>

<code>            </code><code>inputstream.close();</code>

<code>      </code><code>catch</code> <code>(ioexception ex) {</code>

<code>                </code><code>"ioexception parsing xml document from "</code> <code>+ encodedresource.getresource(), ex);</code>

<code>      </code><code>finally</code> <code>{</code>

<code>         </code><code>currentresources.remove(encodedresource);</code>

<code>         </code><code>if</code> <code>(currentresources.isempty()) {</code>

<code>            </code><code>this</code><code>.resourcescurrentlybeingloaded.remove();</code>

開始構造xml inputsource.

2.2 生成document

<code> </code><code>public</code> <code>document loaddocument(inputsource inputsource, entityresolver entityresolver,</code>

<code>         </code><code>errorhandler errorhandler, </code><code>int</code> <code>validationmode, </code><code>boolean</code> <code>namespaceaware) </code><code>throws</code> <code>exception {</code>

<code>      </code><code>documentbuilderfactory factory = createdocumentbuilderfactory(validationmode, namespaceaware);</code>

<code>      </code><code>if</code> <code>(logger.isdebugenabled()) {</code>

<code>         </code><code>logger.debug(</code><code>"using jaxp provider ["</code> <code>+ factory.getclass().getname() + </code><code>"]"</code><code>);</code>

<code>      </code><code>documentbuilder builder = createdocumentbuilder(factory, entityresolver, errorhandler);</code>

<code>      </code><code>return</code> <code>builder.parse(inputsource);</code>

2.3構造document建造工廠

<code>  </code><code>protected</code> <code>documentbuilderfactory createdocumentbuilderfactory(</code><code>int</code> <code>validationmode, </code><code>boolean</code> <code>namespaceaware)</code>

<code>         </code><code>throws</code> <code>parserconfigurationexception {</code>

<code>      </code><code>documentbuilderfactory factory = documentbuilderfactory.newinstance();</code>

<code>      </code><code>factory.setnamespaceaware(namespaceaware);</code>

<code>      </code><code>//根據擷取的驗證模式,決定為factory開啟xsd開關</code>

<code>      </code><code>if</code> <code>(validationmode != xmlvalidationmodedetector.validation_none) {</code>

<code>         </code><code>factory.setvalidating(</code><code>true</code><code>);</code>

<code>         </code><code>if</code> <code>(validationmode == xmlvalidationmodedetector.validation_xsd) {</code>

<code>            </code><code>// enforce namespace aware for xsd...</code>

<code>            </code><code>factory.setnamespaceaware(</code><code>true</code><code>);</code>

<code>            </code><code>try</code> <code>{</code>

<code>                </code><code>factory.setattribute(schema_language_attribute, xsd_schema_language);</code>

<code>            </code><code>catch</code> <code>(illegalargumentexception ex) {</code>

<code>                </code><code>parserconfigurationexception pcex = </code><code>new</code> <code>parserconfigurationexception(</code>

<code>                      </code><code>"unable to validate using xsd: your jaxp provider ["</code> <code>+ factory +</code>

<code>                      </code><code>"] does not support xml schema. are you running on java 1.4 with apache crimson? "</code> <code>+</code>

<code>                      </code><code>"upgrade to apache xerces (or java 1.5) for full xsd support."</code><code>);</code>

<code>                </code><code>pcex.initcause(ex);</code>

<code>                </code><code>throw</code> <code>pcex;</code>

<code>      </code><code>return</code> <code>factory;</code>

這時候一目了然了。

通過檢視日志,最後我們得出我們想要的結果。

using jaxp provider [com.sun.org.apache.xerces.internal.jaxp.documentbuilderfactoryimpl]

com.sun.org.apache.xerces.internal.jaxp.documentbuilderfactoryimpl

com.sun.org.apache.xerces.internal.jaxp.documentbuilderimpl

到了這裡,document對象我們已經拿到了,開始進行解析。

void org.springframework.beans.factory.xml.defaultbeandefinitiondocumentreader.doregisterbeandefinitions(element root)

3.1根據環境中profile參數,解析需要元素&lt;beans&gt;。

<code>protected</code> <code>beandefinitionparserdelegate createdelegate(</code>

<code>         </code><code>xmlreadercontext readercontext, element root, beandefinitionparserdelegate parentdelegate) {</code>

<code>      </code><code>beandefinitionparserdelegate delegate = createhelper(readercontext, root, parentdelegate);</code>

<code>      </code><code>if</code> <code>(delegate == </code><code>null</code><code>) {</code>

<code>         </code><code>delegate = </code><code>new</code> <code>beandefinitionparserdelegate(readercontext, getenvironment());</code>

<code>         </code><code>delegate.initdefaults(root, parentdelegate);</code>

<code>      </code><code>return</code> <code>delegate;</code>

<code>   </code><code>/**</code>

<code>    </code><code>* 初始化預設參數:lazy-init, autowire, dependency check settings,</code>

<code>    </code><code>* init-method, destroy-method and merge settings. </code>

<code>    </code><code>*如果沒有顯示設定,使用上級預設參數。</code>

<code>    </code><code>*/</code>

<code>   </code><code>publicvoid initdefaults(element root, beandefinitionparserdelegate parent) {</code>

<code>      </code><code>populatedefaults(</code><code>this</code><code>.defaults, (parent != </code><code>null</code> <code>? parent.defaults : </code><code>null</code><code>), root);</code>

<code>      </code><code>this</code><code>.readercontext.firedefaultsregistered(</code><code>this</code><code>.defaults);</code>

下面正式進入正題,子元素的解析(如bean)

3.2 分别解析bean标簽和自定義标簽(對應于xml中元素)

void org.springframework.beans.factory.xml.defaultbeandefinitiondocumentreader.parsebeandefinitions(element root, beandefinitionparserdelegate delegate)

<code>  </code><code>protectedvoid parsebeandefinitions(element root, beandefinitionparserdelegate delegate) {</code>

<code>      </code><code>if</code> <code>(delegate.isdefaultnamespace(root)) {</code>

<code>         </code><code>nodelist nl = root.getchildnodes();</code>

<code>         </code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; nl.getlength(); i++) {</code>

<code>            </code><code>node node = nl.item(i);</code>

<code>            </code><code>if</code> <code>(node </code><code>instanceof</code> <code>element) {</code>

<code>                </code><code>element ele = (element) node;</code>

<code>                </code><code>if</code> <code>(delegate.isdefaultnamespace(ele)) {</code>

<code>                   </code><code>parsedefaultelement(ele, delegate);</code>

<code>                </code><code>}</code>

<code>                </code><code>else</code> <code>{</code>

<code>                   </code><code>delegate.parsecustomelement(ele);</code>

<code>      </code><code>else</code> <code>{</code>

<code>         </code><code>delegate.parsecustomelement(root);</code>

parsecustomelement()方法暫時忽略,到自定義标簽時,再進行分析。

此刻,我們需要關注的是parsedefaultelement()。

3.3具體分别處理import,alias,bean,beans子元素。

<code>   </code><code>private</code> <code>void</code> <code>parsedefaultelement(element ele, beandefinitionparserdelegate delegate) {</code>

<code>      </code><code>if</code> <code>(delegate.nodenameequals(ele, import_element)) {</code>

<code>         </code><code>importbeandefinitionresource(ele);</code>

<code>      </code><code>elseif (delegate.nodenameequals(ele, alias_element)) {</code>

<code>         </code><code>processaliasregistration(ele);</code>

<code>      </code><code>elseif (delegate.nodenameequals(ele, bean_element)) {</code>

<code>         </code><code>processbeandefinition(ele, delegate);</code>

<code>      </code><code>elseif (delegate.nodenameequals(ele, nested_beans_element)) {</code>

<code>         </code><code>// recurse</code>

<code>         </code><code>doregisterbeandefinitions(ele);</code>

3.4處理import标簽

<code>   </code><code>void</code> <code>org.springframework.beans.factory.xml.defaultbeandefinitiondocumentreader.importbeandefinitionresource(element ele)</code>

<code>protected</code> <code>void</code> <code>importbeandefinitionresource(element ele) {</code>

<code>      </code><code>string location = ele.getattribute(resource_attribute);</code>

<code>//略:處理路徑,擷取資源</code>

<code>            </code><code>int</code> <code>importcount = getreadercontext().getreader().loadbeandefinitions(location, actualresources);</code>

<code>            </code><code>if</code> <code>(logger.isdebugenabled()) {</code>

<code>                </code><code>logger.debug(</code><code>"imported "</code> <code>+ importcount + </code><code>" bean definitions from url location ["</code> <code>+ location + </code><code>"]"</code><code>);</code>

<code>         </code><code>catch</code> <code>(beandefinitionstoreexception ex) {</code>

<code>            </code><code>getreadercontext().error(</code>

<code>                   </code><code>"failed to import bean definitions from url location ["</code> <code>+ location + </code><code>"]"</code><code>, ele, ex);</code>

<code>//其他</code>

<code>}</code>

3.5處理alias标簽

40

41

<code>  </code><code>protected</code> <code>void</code> <code>processaliasregistration(element ele) {</code>

<code>      </code><code>string name = ele.getattribute(name_attribute);</code>

<code>      </code><code>string alias = ele.getattribute(alias_attribute);</code>

<code>      </code><code>boolean</code> <code>valid = </code><code>true</code><code>;</code>

<code>    </code><code>//驗證資訊有效性</code>

<code>      </code><code>if</code> <code>(valid) {</code>

<code>            </code><code>getreadercontext().getregistry().registeralias(name, alias);</code>

<code>         </code><code>catch</code> <code>(exception ex) {</code>

<code>            </code><code>getreadercontext().error(</code><code>"failed to register alias '"</code> <code>+ alias +</code>

<code>                   </code><code>"' for bean with name '"</code> <code>+ name + </code><code>"'"</code><code>, ele, ex);</code>

<code>         </code><code>getreadercontext().firealiasregistered(name, alias, extractsource(ele));</code>

<code>void</code> <code>org.springframework.context.support.genericapplicationcontext.registeralias(string beanname, string alias)</code>

<code>   </code><code>publicvoid registeralias(string beanname, string alias) {</code>

<code>      </code><code>this</code><code>.beanfactory.registeralias(beanname, alias);</code>

<code>  </code><code>void</code> <code>org.springframework.core.simplealiasregistry.registeralias(string name, string alias) </code>

<code>   </code><code>public</code> <code>void</code> <code>registeralias(string name, string alias) {</code>

<code>      </code><code>assert.hastext(name, </code><code>"'name' must not be empty"</code><code>);</code>

<code>      </code><code>assert.hastext(alias, </code><code>"'alias' must not be empty"</code><code>);</code>

<code>      </code><code>if</code> <code>(alias.equals(name)) {</code>

<code>         </code><code>this</code><code>.aliasmap.remove(alias);</code>

<code>         </code><code>if</code> <code>(!allowaliasoverriding()) {</code>

<code>            </code><code>string registeredname = </code><code>this</code><code>.aliasmap.get(alias);</code>

<code>            </code><code>if</code> <code>(registeredname != </code><code>null</code> <code>&amp;&amp; !registeredname.equals(name)) {</code>

<code>                </code><code>thrownew illegalstateexception(</code><code>"cannot register alias '"</code> <code>+ alias + </code><code>"' for name '"</code> <code>+</code>

<code>                      </code><code>name + </code><code>"': it is already registered for name '"</code> <code>+ registeredname + </code><code>"'."</code><code>);</code>

<code>         </code><code>checkforaliascircle(name, alias);</code>

<code>         </code><code>this</code><code>.aliasmap.put(alias, name);</code>

3.6解析bean,重中之重,每一步都進行分析。

void org.springframework.beans.factory.xml.defaultbeandefinitiondocumentreader.processbeandefinition(element ele, beandefinitionparserdelegate delegate)

<code>  </code><code>protected</code> <code>void</code> <code>processbeandefinition(element ele, beandefinitionparserdelegate delegate) {</code>

<code>      </code><code>beandefinitionholder bdholder = delegate.parsebeandefinitionelement(ele);</code>

<code>      </code><code>if</code> <code>(bdholder != </code><code>null</code><code>) {</code>

<code>         </code><code>bdholder = delegate.decoratebeandefinitionifrequired(ele, bdholder);</code>

<code>            </code><code>// register the final decorated instance.</code>

<code>            </code><code>beandefinitionreaderutils.registerbeandefinition(bdholder, getreadercontext().getregistry());</code>

<code>            </code><code>getreadercontext().error(</code><code>"failed to register bean definition with name '"</code> <code>+</code>

<code>                   </code><code>bdholder.getbeanname() + </code><code>"'"</code><code>, ele, ex);</code>

<code>         </code><code>// send registration event.</code>

<code>         </code><code>getreadercontext().firecomponentregistered(</code><code>new</code> <code>beancomponentdefinition(bdholder));</code>

3.7

beandefinitionholder org.springframework.beans.factory.xml.beandefinitionparserdelegate.parsebeandefinitionelement(element ele, beandefinition containingbean)

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

<code>  </code><code>public</code> <code>beandefinitionholder parsebeandefinitionelement(element ele, beandefinition containingbean) {</code>

<code>      </code><code>string id = ele.getattribute(id_attribute);</code>

<code>      </code><code>string nameattr = ele.getattribute(name_attribute);</code>

<code>      </code><code>//處理别名</code>

<code>      </code><code>list&lt;string&gt; aliases = </code><code>new</code> <code>arraylist&lt;string&gt;();</code>

<code>      </code><code>if</code> <code>(stringutils.haslength(nameattr)) {</code>

<code>         </code><code>string[] namearr = stringutils.tokenizetostringarray(nameattr, multi_value_attribute_delimiters);</code>

<code>         </code><code>aliases.addall(arrays.aslist(namearr));</code>

<code>      </code><code>//設定名稱</code>

<code>      </code><code>string beanname = id;</code>

<code>      </code><code>if</code> <code>(!stringutils.hastext(beanname) &amp;&amp; !aliases.isempty()) {</code>

<code>         </code><code>beanname = aliases.remove(</code><code>0</code><code>);</code>

<code>         </code><code>if</code> <code>(logger.isdebugenabled()) {</code>

<code>            </code><code>logger.debug(</code><code>"no xml 'id' specified - using '"</code> <code>+ beanname +</code>

<code>                   </code><code>"' as bean name and "</code> <code>+ aliases + </code><code>" as aliases"</code><code>);</code>

<code>      </code><code>//判斷名稱,唯一性</code>

<code>      </code><code>if</code> <code>(containingbean == </code><code>null</code><code>) {</code>

<code>         </code><code>checknameuniqueness(beanname, aliases, ele);</code>

<code>      </code><code>abstractbeandefinition beandefinition = parsebeandefinitionelement(ele, beanname, containingbean);</code>

<code>      </code><code>if</code> <code>(beandefinition != </code><code>null</code><code>) {</code>

<code>         </code><code>//建立關系bd 與名稱映射關系</code>

<code>         </code><code>if</code> <code>(!stringutils.hastext(beanname)) {</code>

<code>                </code><code>if</code> <code>(containingbean != </code><code>null</code><code>) {</code>

<code>                   </code><code>beanname = beandefinitionreaderutils.generatebeanname(</code>

<code>                         </code><code>beandefinition, </code><code>this</code><code>.readercontext.getregistry(), </code><code>true</code><code>);</code>

<code>                   </code><code>beanname = </code><code>this</code><code>.readercontext.generatebeanname(beandefinition);</code>

<code>                   </code><code>// register an alias for the plain bean class name, if still possible,</code>

<code>                   </code><code>// if the generator returned the class name plus a suffix.</code>

<code>                   </code><code>// this is expected for spring 1.2/2.0 backwards compatibility.</code>

<code>                   </code><code>string beanclassname = beandefinition.getbeanclassname();</code>

<code>                   </code><code>if</code> <code>(beanclassname != </code><code>null</code> <code>&amp;&amp;</code>

<code>                         </code><code>beanname.startswith(beanclassname) &amp;&amp; beanname.length() &gt; beanclassname.length() &amp;&amp;</code>

<code>                         </code><code>!</code><code>this</code><code>.readercontext.getregistry().isbeannameinuse(beanclassname)) {</code>

<code>                      </code><code>aliases.add(beanclassname);</code>

<code>                   </code><code>}</code>

<code>                </code><code>if</code> <code>(logger.isdebugenabled()) {</code>

<code>                   </code><code>logger.debug(</code><code>"neither xml 'id' nor 'name' specified - "</code> <code>+</code>

<code>                         </code><code>"using generated bean name ["</code> <code>+ beanname + </code><code>"]"</code><code>);</code>

<code>            </code><code>catch</code> <code>(exception ex) {</code>

<code>                </code><code>error(ex.getmessage(), ele);</code>

<code>                </code><code>return</code> <code>null</code><code>;</code>

<code>         </code><code>string[] aliasesarray = stringutils.tostringarray(aliases);</code>

<code>         </code><code>returnnew beandefinitionholder(beandefinition, beanname, aliasesarray);</code>

<code>      </code><code>return</code> <code>null</code><code>;</code>

3.8

 abstractbeandefinition org.springframework.beans.factory.xml.beandefinitionparserdelegate.parsebeandefinitionelement(element ele, string beanname, beandefinition containingbean)

<code>  </code><code>public</code> <code>abstractbeandefinition parsebeandefinitionelement(</code>

<code>         </code><code>element ele, string beanname, beandefinition containingbean) {</code>

<code>      </code><code>this</code><code>.parsestate.push(</code><code>new</code> <code>beanentry(beanname));</code>

<code>      </code><code>string classname = </code><code>null</code><code>;</code>

<code>      </code><code>if</code> <code>(ele.hasattribute(class_attribute)) {</code>

<code>         </code><code>classname = ele.getattribute(class_attribute).trim();</code>

<code>         </code><code>string parent = </code><code>null</code><code>;</code>

<code>         </code><code>if</code> <code>(ele.hasattribute(parent_attribute)) {</code>

<code>            </code><code>parent = ele.getattribute(parent_attribute);</code>

<code>         </code><code>//初始化bd</code>

<code>         </code><code>abstractbeandefinition bd = createbeandefinition(classname, parent);</code>

<code>         </code><code>//賦bd屬性(scope,lazy-init,abstract...)</code>

<code>         </code><code>parsebeandefinitionattributes(ele, beanname, containingbean, bd);</code>

<code>         </code><code>bd.setdescription(domutils.getchildelementvaluebytagname(ele, description_element));</code>

<code>         </code><code>parsemetaelements(ele, bd);</code>

<code>         </code><code>//lookup-method</code>

<code>         </code><code>parselookupoverridesubelements(ele, bd.getmethodoverrides());</code>

<code>         </code><code>//replaced-method</code>

<code>         </code><code>parsereplacedmethodsubelements(ele, bd.getmethodoverrides());</code>

<code>         </code><code>parseconstructorargelements(ele, bd);</code>

<code>         </code><code>parsepropertyelements(ele, bd);</code>

<code>         </code><code>//qualifier</code>

<code>         </code><code>parsequalifierelements(ele, bd);</code>

<code>         </code><code>bd.setresource(</code><code>this</code><code>.readercontext.getresource());</code>

<code>         </code><code>bd.setsource(extractsource(ele));</code>

<code>         </code><code>return</code> <code>bd;</code>

<code>      </code><code>catch</code> <code>(classnotfoundexception ex) {</code>

<code>         </code><code>error(</code><code>"bean class ["</code> <code>+ classname + </code><code>"] not found"</code><code>, ele, ex);</code>

<code>      </code><code>catch</code> <code>(noclassdeffounderror err) {</code>

<code>         </code><code>error(</code><code>"class that bean class ["</code> <code>+ classname + </code><code>"] depends on not found"</code><code>, ele, err);</code>

<code>      </code><code>catch</code> <code>(throwable ex) {</code>

<code>         </code><code>error(</code><code>"unexpected failure during bean definition parsing"</code><code>, ele, ex);</code>

<code>         </code><code>this</code><code>.parsestate.pop();</code>

<code>      </code><code>returnnull;</code>

到這裡,就不繼續探究了。下面就是逐次調用類似ele.getattribute()從xml取值,bd.setxxx()指派的過程。

比較重要的對象。

beandefinition為xml &lt;bean&gt;标簽資料載體對象。通過分析,可以找到xml對應節點或屬性,大部分都可以在abstractbeandefinition中找到。

beandefinition是支援層級的,在這兒就不重點分析了。

死磕Spring系列之三,XML解析相關
死磕Spring系列之三,XML解析相關

xml解析相關類圖

死磕Spring系列之三,XML解析相關