在spring中,所有的bean都是由BeanFactory進行管理的。下面是BeanFactory的類體系結構:
我們清楚的看到,DefaultListableBeanFactory繼承了BeanFactory的優良傳統,同時又實現了BeanDefinitionRegistry這個注冊器,那么無疑,BeanDefinition在容器中的注冊任務,非他莫屬。事實上,DefaultListableBeanFactory擁有一個私有的BeanDefinitonMap屬性,這個屬性是個哈希Map,通過把解析好的BeanDefiniton放到哈希Map中,就完成了注冊。下面是注冊方法:
1 //--------------------------------------------------------------------- 2 // Implementation of BeanDefinitionRegistry interface 3 //--------------------------------------------------------------------- 4 5 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 6 throws BeanDefinitionStoreException { 7 8 。。。。。。40 41 this.beanDefinitionMap.put(beanName, beanDefinition); 42 43 44 resetBeanDefinition(beanName); 45 } 46 }
第41行把beanDefinition作為value,而把beanName作為key,放到beanDefinitionMap中,就完成了注冊。那么,這個beanDefinition是從哪里傳過來的呢?
由於我的myeclipse環境中使用的是spring源碼,而非jar包,所以我們做一個小測試,我配置一個簡單的<bean>,然后做一個惡簡單的spring容器的啟動和<bean>的加載,那么程序一定會走到41行來執行注冊。我在第41行上面加上一句:beanDefinition=null;這樣的話,執行到第41行就會報錯,報錯信息如下:
。。。。。。 17 Caused by: java.lang.NullPointerException 18 at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:881) 19 at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:628) 20 at org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerBeanDefinition(BeanDefinitionReaderUtils.java:148) 21 at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(DefaultBeanDefinitionDocumentReader.java:263) 22 at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(DefaultBeanDefinitionDocumentReader.java:153) 23 at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:132) 24 at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:93) 25 at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493) 26 at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390) 27 ... 14 more
從第26行倒着往上看,就是整個beanDefinition的加載與注冊過程。大概過程我們一目了然:
1.由XmlBeanDefinitionReader開始加載、注冊。
2.由DefaultBeanDefinitionDocumentReader開始解析。
3.由BeanDefinitionReaderUtils過渡。
4.由DefaultListableBeanFactory注冊。
我們來具體分析一下這四個類。
解讀第1步:Resource在加載了XML文件后,首先是由BeanDefinitionReader來解析的。下面是BeanDefinitionReader的部分子孫圖和注釋:
解讀第2步:那么第二步所說的DefaultBeanDefinitionDocumentReader應該就是圖中提到的"BeanDefinitionDocumentReader"的某個子孫了。它負責與BeanDefinitionRegistry的實現者對話。而這個"BeanDefinitionRegistry的實現者"就是DefaultListableBeanFactory。
BeanDefinitionDocumentReader的家族圖也很簡單,它的家譜圖說明:
解讀第3步:過渡類。
解讀第4步:文章一開始已經分析過了。實際上,DefaultListableBeanFactory能做的事情很多,除了注冊BeanDefinition外,它可以被用作一個獨立的BeanFactory,又可以被基本的BeanFactory子類來繼承,打開API文檔你會看到,DefaultListableBeanFactory繼承和實現了一堆父類,親爹干爹一大堆,API上描述其為:"a full-fledged bean factory"(羽翼豐滿的bean factory),下面是它的親爹和干爹們:
沒錯,在spring王國里,它就是富二代。