應用開發中的容器,是指應用代碼的運行框架。不基於容器的開發,是雜亂無章的,事實上,不少架構或者應用都是以容器爲基礎的,好比:EJB就是過去管理J2EE業務對象時最經常使用的容器。而J2EE的Web容器則比較特殊,它是用於管理servlet及其相關依賴對象的,Tomcat就是一個很是典型的Web容器。通常而言,容器都包含有好比生命週期管理、查找、配置管理以及依賴決策等基礎服務,並且還會根據狀況提供一些線程管理、對象池等增值服務。應用對象(大多數時候狀況下,是業務邏輯)在容器裏運行,也就是咱們所謂的「被容器管理」。其實從Java剛剛問世不久,程序員們對容器在J2EE開發中的重要性已經有了比較清楚的認識,由於它能夠極大地較低維護和管理的成本,也能進行接口和實體分離,以此下降耦合以及避免對Singleton的硬編程。合理的使用容器,能夠很好的簡化開發,然而,早期的重量級框架卻都經過應用繼承它們的類或實現它們的接口讓應用與框架綁死。一個很典型的例子是EJB 2的無狀態會話Bean。EJB 2並非特例,其餘流行框架也是如此,例如早期的Struts、WebWork 和 Tapestry,它們都存在強迫開發者編寫大量冗餘代碼、應用與框架綁定等等缺陷。而輕量級容器就是爲解決這些問題,而應運而生的。固然,咱們稱之爲「輕量級容器」的架構,並無徹底脫離EJB架構的軌跡,它與EJB甚至有些相像:兩者都是由容器管理業務對象,而後在圍繞着這個服務層(對業務對象容器的改革是Spring關注的重點)組織整個架構。java
儘管輕量級容器並非Rod Johnson的獨創,實際上它在2003年就已經氾濫,而控制輕量級容器的另外一個核心依賴注入以及其核心要素依賴倒置原則,其實早已在EJB 2.5 和早期Tomcat身上就能夠看到,在與Martin Fowler等人的早期技術討論中,Rod Johnson明確了控制反轉和依賴注入在將來編程中的重要性。並在隨後發表的著做《Expert One-on-One J2EE Development without EJB》中,首次系統的闡述了輕量級容器,配合當時新興的控制反轉以減少代碼對輕量級容器的依賴,同時對於當時單純的控制反轉在協做對象等等方面的不足提出了全新的解決辦法,從而與Aop一塊兒構建出全新的架構核心,並以此構建出全新的輕量級J2EE應用程序框架,在全新的Ioc容器中使用POJO業務對象而且由容器負責使用AOP提供聲明式的企業級服務。但願藉此來規避過去EJB種種的複雜性,去完成過去只有EJB才能作到的事,這即是Spring Ioc容器的設計初衷。node
IoC也被稱做依賴注入(DI)。它是一個處理對象依賴項的過程,也就是將他們一塊兒工做的其餘的對象,只有經過構造參數、工廠方法參數或者(屬性注入)經過構造參數實例化或經過工廠方法返回對象後再設置屬性。當建立bean後,IoC容器再將這些依賴項注入進去。這個過程基本上是反轉的,所以得名控制反轉(IoC)。程序員
下圖是 IoC 的高級別視圖web
IoC容器利用Java的POJO類和配置元數據來生成 徹底配置和可執行 的系統或應用程序。而Bean在Spring中就是POJO,也能夠認爲Bean就是對象。spring
Spring做爲面向對象編程的集大成之做,咱們直接從接口入手能夠幫助咱們更直觀的瞭解Ioc容器的設計原理。express
注1:筆者未能找到最新的Spring 4.0 接口體系圖片,因此接口體系用都是Spring-3.1 接口體系,而分析的Sping 源碼版本爲:Spring-4.3。其實原本打算從新繪製新的接口體系,但分析過程當中也發現二者鮮有差別,因此爲了節省時間,固延用了老的版本。編程
注2:主要參考了《Spring技術內幕》第二版,但他的思惟太過跳躍,因此我從新作了編排,還有就是不少細節部分參考了《Spring源碼深度解析》,固然由於源碼版本的不一樣,也會有些許差別。設計模式
下圖描述了Ioc容器中的主要接口設計
數組
這裏主要是接口體系,而具體實現體系,好比DefaultListableBeanFactory就是爲了實現ConfigurableBeanFactory,從而成爲一個簡單Ioc容器實現。與其餘Ioc容器相似,XmlBeanFactory就是爲了實現BeanFactory,但都是基於DefaultListableBeanFactory的基礎作了擴展。一樣的,ApplicationContext也同樣。 緩存
從圖中咱們能夠簡要的作出如下分析:
1.從接口BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,這是一條主要的BeanFactory設計路徑。在這條接口設計路徑中,BeanFactory,是一條主要的BeanFactory設計路徑。在這條接口設計路徑中,BeanFactory接口定義了基本的Ioc容器的規範。在這個接口定義中,包括了getBean()這樣的Ioc容器的基本方法(經過這個方法能夠從容器中取得Bean)。而HierarchicalBeanFactory接口在繼承了BeanFactory的基本接口後,增長了getParentBeanFactory()的接口功能,使BeanFactory具有了雙親Ioc容器的管理功能。在接下來的ConfigurableBeanFactory接口中,主要定義了一些對BeanFactory的配置功能,好比經過setParentBeanFactory()設置雙親Ioc容器,經過addBeanPostProcessor()配置Bean後置處理器,等等。經過這些接口設計的疊加,定義了BeanFactory就是最簡單的Ioc容器的基本功能。
2.第二條接口設計主線是,以ApplicationContext做爲核心的接口設計,這裏涉及的主要接口設計有,從BeanFactory到ListableBeanFactory,再到ApplicationContext,再到咱們經常使用的WebApplicationContext或者ConfigurableApplicationContext接口。咱們經常使用的應用基本都是org.framework.context 包裏的WebApplicationContext或者ConfigurableApplicationContext實現。在這個接口體現中,ListableBeanFactory和HierarchicalBeanFactory兩個接口,鏈接BeanFactory接口定義和ApplicationContext應用的接口定義。在ListableBeanFactory接口中,細化了許多BeanFactory的接口功能,好比定義了getBeanDefinitionNames()接口方法;對於ApplicationContext接口,它經過繼承MessageSource、ResourceLoader、ApplicationEventPublisher接口,在BeanFactory簡單Ioc容器的基礎上添加了許多對高級容器的特性支持。
3.這個接口系統是以BeanFactory和ApplicationContext爲核心設計的,而BeanFactory是Ioc容器中最基本的接口,在ApplicationContext的設計中,一方面,能夠看到它繼承了BeanFactory接口體系中的ListableBeanFactory、AutowireCapableBeanFactory、HierarchicalBeanFactory等BeanFactory的接口,具有了BeanFactory Ioc容器的基本功能;另外一方面,經過繼承MessageSource、ResourceLoadr、ApplicationEventPublisher這些接口,BeanFactory爲ApplicationContext賦予了更高級的Ioc容器特性。對於ApplicationContext而言,爲了在Web環境中使用它,還設計了WebApplicationContext接口,而這個接口經過繼承ThemeSource接口來擴充功能。
恩,咱們與其寫繁瑣的文字,不如直接閱讀代碼來的直接的多。
最原始的容器:BeanFactory
package org.springframework.beans.factory; import org.springframework.beans.BeansException; import org.springframework.core.ResolvableType; /** * BeanFactory做爲最原始同時也最重要的Ioc容器,它主要的功能是爲依賴注入 (DI) 提供支持, BeanFactory 和相關的接口,好比,BeanFactoryAware、 * DisposableBean、InitializingBean,仍舊保留在 Spring 中,主要目的是向後兼容已經存在的和那些 Spring 整合在一塊兒的第三方框架。在 Spring 中 * ,有大量對 BeanFactory 接口的實現。其中,最常被使用的是 XmlBeanFactory 類。這個容器從一個 XML 文件中讀取配置元數據,由這些元數據來生成一 * 個被配置化的系統或者應用。在資源寶貴的移動設備或者基於applet的應用當中, BeanFactory 會被優先選擇。不然,通常使用的是 ApplicationContext * * 這裏定義的只是一系列的接口方法,經過這一系列的BeanFactory接口,可使用不一樣的Bean的檢索方法很方便地從Ioc容器中獲得須要的Bean,從而忽略具體 * 的Ioc容器的實現,從這個角度上看,這些檢索方法表明的是最爲基本的容器入口。 * * @author Rod Johnson * @author Juergen Hoeller * @author Chris Beams * @since 13 April 2001 */ public interface BeanFactory { /** * 轉定義符"&" 用來引用實例,或把它和工廠產生的Bean區分開,就是說,若是一個FactoryBean的名字爲a,那麼,&a會獲得那個Factory * * FactoryBean和BeanFactory 是在Spring中使用最爲頻繁的類,它們在拼寫上很類似。一個是Factory,也就是Ioc容器或對象工廠;一個 * 是Bean。在Spring中,全部的Bean都是由BeanFactory(也就是Ioc容器)來進行管理的。但對FactoryBean而言,這個Bean不是簡單的Be * an,而是一個能產生或者修飾對象生成的工廠Bean,它的實現與設計模式中的工廠模式和修飾器模式相似。 */ String FACTORY_BEAN_PREFIX = "&"; /** * 五個不一樣形式的getBean方法,獲取實例 * @param name 檢索所用的Bean名 * @return Object(<T> T) 實例對象 * @throws BeansException 若是Bean不能取得 */ Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; /** * 讓用戶判斷容器是否含有指定名字的Bean. * @param name 搜索所用的Bean名 * @return boolean 是否包含其中 */ boolean containsBean(String name); /** * 查詢指定名字的Bean是不是Singleton類型的Bean. * 對於Singleton屬性,能夠在BeanDefinition指定. * @param name 搜索所用的Bean名 * @return boolean 是否包是Singleton * @throws NoSuchBeanDefinitionException 沒有找到Bean */ boolean isSingleton(String name) throws NoSuchBeanDefinitionException; /** * 查詢指定名字的Bean是不是Prototype類型的。 * 與Singleton屬性同樣,能夠在BeanDefinition指定. * @param name 搜索所用的Bean名 * @return boolean 是否包是Prototype * @throws NoSuchBeanDefinitionException 沒有找到Bean */ boolean isPrototype(String name) throws NoSuchBeanDefinitionException; /** * 查詢指定了名字的Bean的Class類型是不是特定的Class類型. * @param name 搜索所用的Bean名 * @param typeToMatch 匹配類型 * @return boolean 是不是特定類型 * @throws NoSuchBeanDefinitionException 沒有找到Bean */ boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; /** * 查詢指定名字的Bean的Class類型. * @param name 搜索所用的Bean名 * @return 指定的Bean或者null(沒有找到合適的Bean) * @throws NoSuchBeanDefinitionException 沒有找到Bean */ Class<?> getType(String name) throws NoSuchBeanDefinitionException; /** * 查詢指定了名字的Bean的全部別名,這些都是在BeanDefinition中定義的 * @param name 搜索所用的Bean名 * @return 指定名字的Bean的全部別名 或者一個空的數組 */ String[] getAliases(String name); }
容器的基礎:XmlBeanFactory
package org.springframework.beans.factory.xml; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.core.io.Resource; /** * XmlBeanFactory是BeanFactory的最簡單實現類 * * XmlBeanFactory的功能是創建在DefaultListableBeanFactory這個基本容器的基礎上的,並在這個基本容器的基礎上實行了其餘諸如 * XML讀取的附加功能。XmlBeanFactory使用了DefaultListableBeanFactory做爲基礎類,DefaultListableBeanFactory是一個很重 * 要的Ioc實現,會在下一章進行重點論述。 * * @author Rod Johnson * @author Juergen Hoeller * @author Chris Beams * @since 15 April 2001 */ public class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); /** * 根據給定來源,建立一個XmlBeanFactory * @param resource Spring中對與外部資源的抽象,最多見的是對文件的抽象,特別是XML文件。並且Resource裏面一般 * 是保存了Spring使用者的Bean定義,好比applicationContext.xml在被加載時,就會被抽象爲Resource來處理。 * @throws BeansException 載入或者解析中發生錯誤 */ public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); } /** * 根據給定來源和BeanFactory,建立一個XmlBeanFactory * @param resource Spring中對與外部資源的抽象,最多見的是對文件的抽象,特別是XML文件。並且Resource裏面一般 * 是保存了Spring使用者的Bean定義,好比applicationContext.xml在被加載時,就會被抽象爲Resource來處理。 * @param parentBeanFactory 父類的BeanFactory * @throws BeansException 載入或者解析中發生錯誤 */ public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); } }
最原始Ioc容器的使用
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; /** * 最原始的Ioc容器使用,固然這也是Spring容器中效率最高的用法,比起繁瑣的文字,閱讀源碼來得直觀得多。 * 只須要寫兩行代碼就好了,固然前提是要準備好Spring的配置文件 * * @author kay * @since 1.0 */ @SuppressWarnings("deprecation") public class SimpleBeanFactory { public static void main(String[] args) { ClassPathResource resource = new ClassPathResource("applicationContext.xml"); BeanFactory beanFactory = new XmlBeanFactory(resource); Message message = beanFactory.getBean("message", Message.class); //Message是本身寫的測試類 message.printMessage(); } }
下面是XmlBeanFactory在使用過程中涉及到的類的關係圖
圖中空心三角加實線表明繼承、空心三角加虛線表明實現、實線箭頭加虛線表明依賴、實心菱形加實線表明組合。這裏用下劃線表明接口,沒有下劃線的表明類。
看着很是複雜是吧,沒關係,咱們以代碼來作簡要說明
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.io.ClassPathResource; /** * 這是與SimpleBeanFactory等效的編程式使用Ioc容器 * * 從中我也能夠看到一些Ioc的基本原理,同時也揭示了Ioc實現中的一些關鍵類:如Resource、DefaultListableBeanFactory * 以及BeanDefinitionReader等等 * * @author kay * @since 1.0 */ public class ProgramBeanFactory{ public static void main(String[] args) { ClassPathResource resource = new ClassPathResource("applicationContext.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(resource); Message message = factory.getBean("message", Message.class); //Message是本身寫的測試類 message.printMessage(); } }
以上,能夠簡單說明咱們在使用Ioc容器時,須要以下幾個步驟:
1,建立Ioc配置文件的抽象資源,這個抽象資源包含了BeanDefinition的定義信息。
2,建立一個BeanFactory,這裏使用了DefaultListableBeanFactory。
3,建立一個載入BeanDefinition的讀取器,這裏使用XmlBeanDefinitionReader來載入XML文件形式的BeanDefinition,經過一個回調配置給BeanFactory。
4,從定義好的資源位置讀入配置信息,具體的解析過程由XmlBeanDefinitionReader來完成。完成整個載入和註冊Bean定義以後,須要的Ioc容器就創建起來了。這個時候咱們就能夠直接使用Ioc容器了。
恩,如下是Bean在使用過程當中的解析、註冊時效圖,咱們來一步一步分析,它是怎麼在源碼中實現的。
Bean的解析、註冊詳細過程分析
配置文件封裝類:ClassPathResource
在Java中,將不一樣來源的資源抽象成URL,經過註冊不一樣的handler(URLStreamHandler)來處理不一樣來源間的資源讀取邏輯。而URL中卻沒有提供一些基本方法來實現本身的抽象結構。於是Spring對其內部資源,使用了本身的抽象結構:Resource接口來封裝。而ClassPathResource實現類便是對Resource的實現。
Resource接口體系
資源的原始接口爲Resource,它繼承自InputStreamResource,實現了其getInstream方法,這樣全部的資源就是經過該方法來獲取輸入流的。對於資源的加載,也實現了統一,定義了一個資源加載頂級接口ResourceLoader,它默認的加載就是DefaultResourceLoader。
InputStreamSource接口
package org.springframework.core.io; import java.io.IOException; import java.io.InputStream; /** * InputStreamSource 封裝任何能返回InputStream的類,好比File、Classpath下的資源和Byte Array等 * * @author Juergen Hoeller * @since 20.01.2004 */ public interface InputStreamSource { /** * 返回InputStream的類,好比File、Classpath下的資源和Byte Array等 * @return InputStream 返回一個新的InputStream的對象 * @throws IOException 若是資源不能打開則拋出異常 */ InputStream getInputStream() throws IOException; }
Resource接口
package org.springframework.core.io; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URL; /** * Resource接口抽象了全部Spring內部使用到的底層資源:File、URL、Classpath等。 * 同時,對於來源不一樣的資源文件,Resource也有不一樣實現:文件(FileSystemResource)、Classpath資源(ClassPathResource)、 * URL資源(UrlResource)、InputStream資源(InputStreamResource)、Byte數組(ByteArrayResource)等等。 * * @author Juergen Hoeller * @since 28.12.2003 */ public interface Resource extends InputStreamSource { /** * 判斷資源是否存在 * @return boolean 是否存在 */ boolean exists(); /** * 判斷資源是否可讀 * @return boolean 是否可讀 */ boolean isReadable(); /** * 是否處於開啓狀態 * @return boolean 是否開啓 */ boolean isOpen(); /** * 獲得URL類型資源,用於資源轉換 * @return URL 獲得URL類型 * @throws IOException 若是資源不能打開則拋出異常 */ URL getURL() throws IOException; /** * 獲得URI類型資源,用於資源轉換 * @return URI 獲得URI類型 * @throws IOException 若是資源不能打開則拋出異常 */ URI getURI() throws IOException; /** * 獲得File類型資源,用於資源轉換 * @return File 獲得File類型 * @throws IOException 若是資源不能打開則拋出異常 */ File getFile() throws IOException; /** * 獲取資源長度 * @return long 資源長度 * @throws IOException 若是資源不能打開則拋出異常 */ long contentLength() throws IOException; /** * 獲取lastModified屬性 * @return long 獲取lastModified * @throws IOException 若是資源不能打開則拋出異常 */ long lastModified() throws IOException; /** * 建立一個相對的資源方法 * @param relativePath 相對路徑 * @return Resource 返回一個新的資源 * @throws IOException 若是資源不能打開則拋出異常 */ Resource createRelative(String relativePath) throws IOException; /** * 獲取文件名稱 * @return String 文件名稱或者null */ String getFilename(); /** * 獲得錯誤處理信息,主要用於錯誤處理的信息打印 * @return String 錯誤資源信息 */ String getDescription(); }
根據上面的推論,咱們能夠理解爲這兩段代碼,在某種程度來講是徹底等效的
ClassPathResource resource = new ClassPathResource("applicationContext.xml"); InputStream inputStream = resource.getInputStream();
Resource resource = new ClassPathResource("applicationContext.xml"); InputStream inputStream = resource.getInputStream();
這樣獲得InputStream之後,咱們能夠拿來用了。值得一提是,不一樣的實現有不一樣的調用方法,這裏就不展開了。下面是ClassPathResource的具體實現:
ClassPathResource.java
private final String path; private ClassLoader classLoader; public ClassPathResource(String path) { this(path, (ClassLoader) null); //這裏是入口,直接跳入下面的ClassPathResource(String path, ClassLoader classLoader) 中 } public ClassPathResource(String path, ClassLoader classLoader) { Assert.notNull(path, "Path must not be null"); String pathToUse = StringUtils.cleanPath(path); if (pathToUse.startsWith("/")) { pathToUse = pathToUse.substring(1); } this.path = pathToUse; this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); }
忽略給定接口:DefaultListableBeanFactory
這裏 DefaultListableBeanFactory 所起到的是忽略給定接口自動裝配功能。簡單來講,通常 bean 中的功能 A 若是沒有初始化,那麼Spring會自動初始化A,這是Spring的一個特性。但當某些特殊狀況時,B不會初始化,好比:B已經實現了 BeanNameAware接口。能夠說,就是經過其餘方式來解析依賴,相似於 BeanFactory 的 BeanFactoryAware。下面是具體實現:
DefaultListableBeanFactory.java
public DefaultListableBeanFactory() { super(); //直接指向下面 AbstractAutowireCapableBeanFactory() }
AbstractAutowireCapableBeanFactory.java
private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<Class<?>>(); public AbstractAutowireCapableBeanFactory() { super(); ignoreDependencyInterface(BeanNameAware.class); //忽略給定接口自動裝配功能的主要實現處 ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class); } public void ignoreDependencyInterface(Class<?> ifc) { this.ignoredDependencyInterfaces.add(ifc); }
BeanDefinition的載入、解析和註冊:XmlBeanDefinitionReader
這裏是BeanDefinition真正被載入的地方。這個載入過程就是把用戶定義好的Bean表示成Ioc容器內部的數據結構,固然這個數據結構就是BeanDefinition。而BeanDefinition實際上就是POJO對象在Ioc容器中的抽象,經過這個BeanDefinition定義的數據結構,讓Ioc容器可以對POJO對象也就是Bean進行管理。
XmlBeanDefinitionReader.java
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { //loadBeanDefinitions的具體實現,而EncodedResource主要用於對資源文件的處理,而其主要實現方法getReader()在下面有所介紹 return loadBeanDefinitions(new EncodedResource(resource)); } public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } //經過屬性來記錄已經加載的資源 Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } // 調用DefaultResourceLoader的getResources方法完成具體的Resource定位 try { //從EncodedResource中獲取已經封裝的Resource對象並再次從Resource中獲取inputStream InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); //真正的邏輯核心 } finally { inputStream.close(); //關閉inputStream } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } /** * 真正的核心處理部分 * 若是不考慮冗餘的代碼,其實只作三件事: * 1.獲取XML文件的驗證模式 * 2.加載XML,並獲取Document. * 3.返回的Document,註冊Bean */ protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { // 取得XML文件的Document對象, 這個解析過程由DefaultDocumentLoader完成 Document doc = doLoadDocument(inputSource, resource); // 啓動對BeanDefinition解析的詳細過程, 解析過程當中會使用到Spring的Bean配置規則 return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } } protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { //loadDocument直接用於註冊Document,getValidationModeForResource方法做用於XML的加載 return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, getValidationModeForResource(resource), isNamespaceAware()); }
EncodedResource.java
public Reader getReader() throws IOException { if (this.charset != null) { return new InputStreamReader(this.resource.getInputStream(), this.charset); } else if (this.encoding != null) { return new InputStreamReader(this.resource.getInputStream(), this.encoding); } else { return new InputStreamReader(this.resource.getInputStream()); } }
XML文件驗證
獲取XML文件的驗證模式,通常分爲兩步:首先,是XML文件驗證,而後,就是驗證模式的讀取。
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> //XSD方式,用於驗證XML文件的正確性 <bean id="..">...</bean> </beans>
經常使用的XML文件驗證方法有兩種:DTD和XSD,DTD如今基本不用了,而上圖中的spring-beans-4.0.xsd對應在源碼中的org.springframework.beans.factory.xml.spring-beans-4.0.xsd。這裏就不具體介紹了,有興趣能夠本身去研究。
加載XML
Spring中經過getValidationModeForResource方法來獲取上面講的DTD和XSD驗證方法,不過就編程而言,仍是很是簡單的。只是要特別須要注意的是自動檢測驗證模式的實現。
XmlBeanDefinitionReader.java
public static final int VALIDATION_AUTO = XmlValidationModeDetector.VALIDATION_AUTO; public static final int VALIDATION_XSD = XmlValidationModeDetector.VALIDATION_XSD; protected int getValidationModeForResource(Resource resource) { int validationModeToUse = getValidationMode(); //若是手動指定了驗證模式則使用指定的驗證模式 if (validationModeToUse != VALIDATION_AUTO) { return validationModeToUse; } //若是沒有指定,則自動檢測 int detectedMode = detectValidationMode(resource); //自動檢測主要是在detectValidationMode(Resource resource)完成的 if (detectedMode != VALIDATION_AUTO) { return detectedMode; } return VALIDATION_XSD; } protected int detectValidationMode(Resource resource) { if (resource.isOpen()) { throw new BeanDefinitionStoreException( "Passed-in Resource [" + resource + "] contains an open stream: " + "cannot determine validation mode automatically. Either pass in a Resource " + "that is able to create fresh streams, or explicitly specify the validationMode " + "on your XmlBeanDefinitionReader instance."); } InputStream inputStream; try { inputStream = resource.getInputStream(); } catch (IOException ex) { throw new BeanDefinitionStoreException( "Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " + "Did you attempt to load directly from a SAX InputSource without specifying the " + "validationMode on your XmlBeanDefinitionReader instance?", ex); } try { return this.validationModeDetector.detectValidationMode(inputStream); //自動檢測則是給detectValidationMode完成的 } catch (IOException ex) { throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: an error occurred whilst reading from the InputStream.", ex); } }
XmlValidationModeDetector.java
public static final int VALIDATION_NONE = 0; public static final int VALIDATION_AUTO = 1; public static final int VALIDATION_DTD = 2; public static final int VALIDATION_XSD = 3; private static final String DOCTYPE = "DOCTYPE"; public int detectValidationMode(InputStream inputStream) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); try { boolean isDtdValidated = false; String content; while ((content = reader.readLine()) != null) { content = consumeCommentTokens(content); //空或註釋略過 if (this.inComment || !StringUtils.hasText(content)) { continue; } if (hasDoctype(content)) { isDtdValidated = true; break; } //讀取<前的信息 if (hasOpeningTag(content)) { break; } } return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD); } catch (CharConversionException ex) { return VALIDATION_AUTO; } finally { reader.close(); } } private boolean hasDoctype(String content) { return content.contains(DOCTYPE); } private boolean hasOpeningTag(String content) { if (this.inComment) { return false; } int openTagIndex = content.indexOf('<'); return (openTagIndex > -1 && (content.length() > openTagIndex + 1) && Character.isLetter(content.charAt(openTagIndex + 1))); }
獲取Document
經過以上的驗證準備,就能夠進行加載了,而XmlBeanDefinitionReader並無本身去完成,而是給了DocumentLoader接口去完成的,而他調用的是DefaultDocumentLoader.loadDocument方法。loadDocument沒有太多可描述的。因此。。。
XmlBeanDefinitionReader.java
private DocumentLoader documentLoader = new DefaultDocumentLoader(); //EntityResolver主要用於處理前面提到的DTD方法的處理 protected EntityResolver getEntityResolver() { if (this.entityResolver == null) { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader != null) { this.entityResolver = new ResourceEntityResolver(resourceLoader); } else { this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader()); } } return this.entityResolver; }
DefaultDocumentLoader.java
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); }
BeanDefinition的解析
BeanDefinition載入過程其實就是把定義的BeanDefinition在IoC容器中轉化爲一個Spring內部表示的數據結構的過程。IoC容器對Bean的管理和依賴注入的實現,都是經過對其持有的BeanDefinition進行各類相關的操做來完成的。這些BeanDefinition數據在IoC容器中經過一個HashMap來維護。
XmlBeanDefinitionReader.java
private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class; public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 獲得BeanDefinitionDocumentReader來對XML的BeanDefinition進行解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); // 具體的解析過程在BeanDefinitionDocumentReader的registerBeanDefinitions方法中完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); }
DefaultBeanDefinitionDocumentReader.java
public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT; public static final String NESTED_BEANS_ELEMENT = "beans"; public static final String ALIAS_ELEMENT = "alias"; public static final String ALIAS_ATTRIBUTE = "alias"; public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); // 得到Document的根元素 doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } preProcessXml(root); // 解析Bean定義以前, 加強解析過程的可擴展性 parseBeanDefinitions(root, this.delegate); // 從Document的根元素開始進行Bean定義的Document對象 postProcessXml(root); // 解析Bean定義以前, 加強解析過程的可擴展性 this.delegate = parent; } protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); // 獲取Document對象根元素的全部子節點並循環解析 for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); // 解析Spring的Bean規則默認元素節點 } else { delegate.parseCustomElement(ele); // 解析自定義元素節點 } } } } else { delegate.parseCustomElement(root); // 解析自定義元素根節點 } } private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // 解析import元素 importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // 解析alias元素 processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // 解析bean元素 processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 解析內嵌beans元素, 做爲根節點遞歸解析 doRegisterBeanDefinitions(ele); } }
恩,直接從代碼就能夠看出,Spring首先獲取Document的根元素(通常爲<beans/>),而後取得根元素全部的子節點並循環解析這些子節點;若是子節點在Spring默認的命名空間內,則按照Spring Bean定義規則來解析,不然按照自定義的節點解析。在按照Spring Bean定義規則進行解析的parseDefaultElement方法中,完成了對<import/>、<alias/>、<bean/>、<beans/>等元素的解析。
爲了使文章簡短一點,在這裏只關注Spring對<bean>元素的解析過程,其它的解析過程再也不分析。
DefaultBeanDefinitionDocumentReader.java
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 具體的解析委託給BeanDefinitionParserDelegate來完成 // BeanDefinitionHolder是BeanDefinition的封裝類, 封裝了BeanDefinition、Bean的名字和別名, 用它來完成向IoC容器註冊. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
BeanDefinitionParserDelegate.java
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { // 解析Bean定義資源文件中的<Bean>元素,主要處理<Bean>元素的id,name和aliase屬性 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; // 若是<Bean>元素中沒有配置id屬性時, 將別名中的第一個值賦值給beanName if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } // 對<bean>元素進行詳細解析 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); //爲解析的Bean使用別名註冊時, 爲了向後兼容(Spring1.2/2.0給別名添加類名後綴) String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; } public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); // 這裏只讀取<Bean>元素中配置的class名字, 而後載入到BeanDefinition中去 // 只是記錄配置的class名字, 並不實例化, 對象的實例化在依賴注入時完成 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } // 根據<Bean>元素配置的class名稱和parent屬性值建立BeanDefinition, 爲載入Bean定義信息作準備 AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 對當前<Bean>元素中配置的一些屬性進行解析, 如singleton、abstract等 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // 對<Bean>元素的meta(元數據)、lookup-method、replaced-method等子元素進行解析 parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); // 解析<Bean>元素的構造方法參數 parsePropertyElements(ele, bd); // 解析<Bean>元素的<property>設置 parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
<bean>元素解析已經完了,而<bean>元素屬性及其子元素的解析順序爲:1,解析<bean>元素的屬性。2,解析<description>子元素。3,解析<meta>子元素。4,解析<lookup-method/>子元素。5,解析<replaced-method>子元素。6,解析<constructor-arg>子元素。7,解析<property>子元素。8,解析<qualifier>子元素。解析過程當中像<meta>、<qualifier>等子元素都不多使用,而下面就直接解析最經常使用的子元素<property>子元素。
BeanDefinitionParserDelegate.java
public void parsePropertyElements(Element beanEle, BeanDefinition bd) { // 遍歷<bean>全部的子元素 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { parsePropertyElement((Element) node, bd); // 若是是<property>元素, 則對其進行解析 } } } public void parsePropertyElement(Element ele, BeanDefinition bd) { String propertyName = ele.getAttribute(NAME_ATTRIBUTE); // <property>元素name屬性 if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); try { // 若是同一個Bean中已經有相同名字的<property>存在, 直接返回 // 也就是說, 若是一個Bean中定義了兩個名字同樣的<property>元素, 只有第一個起做用. if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } // 解析<property>元素, 返回的對象對應<property>元素的解析結果, 最終封裝到PropertyValue中, 並設置到BeanDefinitionHolder中 Object val = parsePropertyValue(ele, bd, propertyName); PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } } public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // 檢查<property>的子元素, 只能是ref, value, list等(description, meta除外)其中的一個. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } // 判斷property元素是否含有ref和value屬性, 不容許既有ref又有value屬性. // 同時也不容許ref和value屬性其中一個與子元素共存. boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } // 若是屬性是ref屬性, 建立一個ref的數據對象RuntimeBeanReference, 封裝了ref信息 if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { // 若是屬性是value屬性, 建立一個數據對象TypedStringValue, 封裝了value信息 TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { // 若是當前<property>元素還有子元素 return parsePropertySubElement(subElement, bd); } else { // propery元素既沒有ref或value屬性, 也沒有子元素, 解析出錯返回null error(elementName + " must specify a ref or value", ele); return null; } }
恩,其實<property>元素還有子元素。
BeanDefinitionParserDelegate.java
public Object parsePropertySubElement(Element ele, BeanDefinition bd) { return parsePropertySubElement(ele, bd, null); } public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if (!isDefaultNamespace(ele)) { // 若是子元素沒有使用Spring默認命名空間, 則使用用戶自定義的規則解析 return parseNestedCustomElement(ele, bd); } else if (nodeNameEquals(ele, BEAN_ELEMENT)) { // 若是子元素是bean元素, 則使用解析<bean>元素的方法解析 BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { // 若是子元素是ref, 有且只能有bean、local和parent 3個屬性中的一個 String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); // 引用普通任意的bean boolean toParent = false; if (!StringUtils.hasLength(refName)) { refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); // 引用同一個XML配置文件中的bean if (!StringUtils.hasLength(refName)) { refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); // 引用父容器中的bean toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean', 'local' or 'parent' is required for <ref> element", ele); return null; } } } // ref元素沒有bean、local和parent 3個屬性中的一個, 返回null. if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } else if (nodeNameEquals(ele, IDREF_ELEMENT)) { // 若是子元素是<idref>, 使用解析idref元素的方法解析 return parseIdRefElement(ele); } else if (nodeNameEquals(ele, VALUE_ELEMENT)) { // 子元素是<value> return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, NULL_ELEMENT)) { // 子元素是<null> TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { // 子元素是<array> return parseArrayElement(ele, bd); } else if (nodeNameEquals(ele, LIST_ELEMENT)) { // 子元素是<list> return parseListElement(ele, bd); } else if (nodeNameEquals(ele, SET_ELEMENT)) { // 子元素是<set> return parseSetElement(ele, bd); } else if (nodeNameEquals(ele, MAP_ELEMENT)) { // 子元素是<map> return parseMapElement(ele, bd); } else if (nodeNameEquals(ele, PROPS_ELEMENT)) { // 子元素是<props> return parsePropsElement(ele); } else { // 以上都不是, 說明配置錯誤, 返回null. error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } }
咱們以<list>子元素進行分析
BeanDefinitionParserDelegate.java
public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) { // 獲取<list>元素中的value-type屬性, 即集合元素的數據類型 String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = collectionEle.getChildNodes(); // <list>元素全部子節點 ManagedList<Object> target = new ManagedList<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); parseCollectionElements(nl, target, bd, defaultElementType); // 具體解析List元素中的值 return target; } protected void parseCollectionElements( NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) { // 遍歷集合全部子節點 for (int i = 0; i < elementNodes.getLength(); i++) { Node node = elementNodes.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) { // 若是子節點是Element且不是<description>節點, 則添加進ManagedList. // 同時觸發對下層子元素的解析, 遞歸調用. target.add(parsePropertySubElement((Element) node, bd, defaultElementType)); } } }
很差意思,沒子類了,BeanDefinition就被載入到IoC容器後,就能夠在容器中創建了數據映射了。剩下的就是BeanDefinition註冊了。
BeanDefinition的註冊
BeanDefinition信息已經在IoC容器內部創建起了本身的數據結構,但這些數據還不能供IoC容器直接使用,須要在IoC容器中對這些BeanDefinition數據進行註冊。不一樣的解析元素解析方式都不一樣但最後的註冊的方式是同樣的,咱們仍是以上面提到的<bean>元素爲例。
BeanDefinitionReaderUtils.java
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); // 向IoC容器註冊BeanDefinition registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // 若是解析的BeanDefinition有別名, 向容器爲其註冊別名. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
上面的registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())是調用的註冊位置,而BeanDefinitionRegistry僅僅是一個接口,而真正實現它的倒是最本來的DefaultListableBeanFactory.registerBeanDefinition方法,值得一提的是DefaultListableBeanFactory.registerBeanDefinition方法在最新的Spring 4.0中穩定性方面作了很大改善。
DefaultListableBeanFactory.java
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); // 對解析獲得的BeanDefinition校驗 if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // 註冊的過程當中須要線程同步, 以保證數據的一致性 synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // 沒有同名BeanDefinition註冊過, 將Bean名字存入beanDefinitionNames this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
至此,註冊完畢後,容器就可用了。雖然這是最原始的容器。
恩,與上一章同樣,直接上代碼。
應用開發容器:ApplicationContext
package org.springframework.context; import org.springframework.beans.factory.HierarchicalBeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.core.env.EnvironmentCapable; import org.springframework.core.io.support.ResourcePatternResolver; /** * ApplicationContext是spring中較高級的容器。和BeanFactory相似,它能夠加載配置文件中定義的bean,將全部的bean集中在一塊兒,當有請求的 * 時候分配bean。 另外,它增長了企業所須要的功能,好比,從屬性文件從解析文本信息和將事件傳遞給所指定的監聽器。這個容器在org.springframework. * context.ApplicationContext接口中定義。ApplicationContext包含BeanFactory全部的功能,通常狀況下,相對於BeanFactory,ApplicationContext * 會被推薦使用。但BeanFactory仍然能夠在輕量級應用中使用,好比移動設備或者基於applet的應用程序。 * * ApplicationContext接口關係 * 1.支持不一樣的信息源。擴展了MessageSource接口,這個接口爲ApplicationContext提供了不少信息源的擴展功能,好比:國際化的實現爲多語言版本的應用提供服務。 * 2.訪問資源。這一特性主要體如今ResourcePatternResolver接口上,對Resource和ResourceLoader的支持,這樣咱們能夠從不一樣地方獲得Bean定義資源。 * 這種抽象使用戶程序能夠靈活地定義Bean定義信息,尤爲是從不一樣的IO途徑獲得Bean定義信息。這在接口上看不出來,不過通常來講,具體ApplicationContext都是 * 繼承了DefaultResourceLoader的子類。由於DefaultResourceLoader是AbstractApplicationContext的基類,關於Resource後面會有更詳細的介紹。 * 3.支持應用事件。繼承了接口ApplicationEventPublisher,爲應用環境引入了事件機制,這些事件和Bean的生命週期的結合爲Bean的管理提供了便利。 * 4.附件服務。EnvironmentCapable裏的服務讓基本的Ioc功能更加豐富。 * 5.ListableBeanFactory和HierarchicalBeanFactory是繼承的主要容器。 * * 最常被使用的ApplicationContext接口實現類: * 1,FileSystemXmlApplicationContext:該容器從XML文件中加載已被定義的bean。在這裏,你須要提供給構造器XML文件的完整路徑。 * 2,ClassPathXmlApplicationContext:該容器從XML文件中加載已被定義的bean。在這裏,你不須要提供XML文件的完整路徑,只需正確配置CLASSPATH * 環境變量便可,由於,容器會從CLASSPATH中搜索bean配置文件。 * 3,WebXmlApplicationContext:該容器會在一個 web 應用程序的範圍內加載在XML文件中 * * @author Rod Johnson * @author Juergen Hoeller */ public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { /** * 獲得這個應用環境的獨一無二ID * @return 獲得這個應用獨一無二的ID,或者返回一個空值 */ String getId(); /** * 獲得這個應用的名稱 * @return 獲得這個應用的名稱,或者返回一個空值 */ String getApplicationName(); /** * 返回這個應用環境的顯示名 * @return 這個應用環境的顯示名,或者返回一個空值 */ String getDisplayName(); /** * 當這個應用第一次載入時,返回一個時間差(ms) * @return 返回一個時間差(ms) */ long getStartupDate(); /** * 獲得一個父類的環境,或者空值 * @return 返回一個父類的環境,或者空值 */ ApplicationContext getParent(); /** * 你可使用它來自動裝配依賴對象,但這是一個很是專業的使用狀況下,你在99.99%的時間是不須要他的。 * @return 這個應用環境的AutowireCapableBeanFactory接口 * @throws IllegalStateException 若是這個應用並不支持AutowireCapableBeanFactory接口,拋出異常 */ AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; }
ApplicationContext的層次結構
ApplicationContext的實現類種類太多,但它們的核心都是將對象工廠功能委託給BeanFactory的實現類DefaultListableBeanFactory,咱們就以經常使用的實現類之一FileSystemXmlApplicationContext來解釋。
ApplicationContext的實現方法:FileSystemXmlApplicationContext
package org.springframework.context.support; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; /** * 在FileSystemXmlApplicationContext的設計中,咱們看到ApplicationContext的主要功能其實已經在AbstractXmlApplicationContext * 中完成了,而在FileSystemXmlApplicationContext只須要完成它自身的兩個功能。 * * 一個就是啓動Ioc容器的refresh()過程。這個會在下一章進行重點論述。 * 另外一個就是加載XML的Bean定義資源,主要是getResourceByPath方法來完成。 * * @author Rod Johnson * @author Juergen Hoeller */ public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext { /** * 建立FileSystemXmlApplicationContext類 */ public FileSystemXmlApplicationContext() { } /** * 根據父類,建立FileSystemXmlApplicationContext類 * @param parent 父類的接口 */ public FileSystemXmlApplicationContext(ApplicationContext parent) { super(parent); } /** * 根據XML文件名,建立FileSystemXmlApplicationContext類 * @param configLocation BeanDefinition所在的文件路徑 * @throws BeansException 若是建立失敗就拋出異常 */ public FileSystemXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } /** * 根據XML文件數組名,建立FileSystemXmlApplicationContext類 * @param configLocations XML文件名,能夠指定多個BeanDefinition資源路徑 * @throws BeansException 若是建立失敗就拋出異常 */ public FileSystemXmlApplicationContext(String... configLocations) throws BeansException { this(configLocations, true, null); } /** * 根據載入的父類接口,以及XML文件名自動刷新環境以及建立FileSystemXmlApplicationContext類 * @param configLocations XML文件名 * @param parent 父類接口,同時指定本身的雙親容器 * @throws BeansException 若是建立失敗就拋出異常 */ public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException { this(configLocations, true, parent); } /** * 根據XML文件名自動刷新環境以及建立FileSystemXmlApplicationContext類 * @param configLocations XML文件名 * @param refresh 是否自動刷新環境 * @throws BeansException 若是建立失敗就拋出異常 */ public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException { this(configLocations, refresh, null); } /** * 根據XML文件名、父類接口、自動刷新環境以及建立FileSystemXmlApplicationContext類 * 調用父類AbstractRefreshableConfigApplicationContext的方法,設置BeanDefinition定義的資源文件,完成IoC容器Bean定義資源的定位 * FileSystemXmlApplicationContext中最重要的實現方法,其餘構建大部分都是基於它,相似的設計也在其餘實現類中得以運用 * * @param configLocations XML文件名 * @param refresh 是否自動刷新環境 * @param parent 父類接口,同時指定本身的雙親容器 * @throws BeansException 若是建立失敗就拋出異常 */ public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); //Ioc容器的refresh()過程,是個很是複雜的過程,但不一樣的容器實現這裏都是類似的,所以基類中就將他們封裝好了 } } /** * 加載XML Bean的給定資源 * 在文件應用中讀取XML中的BeanDefinition以應對不一樣的BeanDefinition讀取方式。 * * @param string 具體路徑 * @return Resource 返回一個具體資源 */ @Override protected Resource getResourceByPath(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); } }
容器的入口:refresh
refresh定義在AbstractApplicationContext類中,它詳細描述了整個ApplicationContext的初始化過程,好比BeanFactory的更新、MessageSource和PostProcessor的註冊等。這裏看起來像是對ApplicationContext進行初始化的模版或執行提綱,這個執行過程爲Bean的生命週期管理提供了條件。
AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 準備刷新容器, 獲取容器的當時時間, 同時給容器設置同步標識 prepareRefresh(); // 啓動子類的refreshBeanFactory方法. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 爲BeanFactory配置容器特性,例如類加載器、事件處理器等. prepareBeanFactory(beanFactory); try { // 設置BeanFactory的後置處理. postProcessBeanFactory(beanFactory); // 調用BeanFactory的後處理器, 這些後處理器是在Bean定義中向容器註冊的. invokeBeanFactoryPostProcessors(beanFactory); // 註冊Bean的後處理器, 在Bean建立過程當中調用. registerBeanPostProcessors(beanFactory); // 初始化上下文中的消息源. initMessageSource(); // 初始化上下文中的事件機制. initApplicationEventMulticaster(); // 初始化其它特殊的Bean. onRefresh(); // 檢查並向容器註冊監聽器Bean. registerListeners(); // 實例化全部剩餘的(non-lazy-init) 單例Bean. finishBeanFactoryInitialization(beanFactory); // 發佈容器事件, 結束refresh過程. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // 銷燬已經建立的單例Bean, 以免資源佔用. destroyBeans(); // 取消refresh操做, 重置 'active' 標誌. cancelRefresh(ex); throw ex; } finally { //重置Spring的核心緩存 resetCommonCaches(); } } }
ApplicationContext容器的使用
咱們以ApplicationContext經常使用容器的使用來,說明容器的運做原理,實現類咱們就用上面的FileSystemXmlApplicationContext,爲何用FileSystemXmlApplicationContext,其實我倒沒什麼立場問題,只是由於他簡單也很具備表明性。而咱們就將啓動過程當中,容器核心部分是如何啓動進行說明。其餘不做說明,由於太過龐雜了。
package com.kay.cn; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; /** * * @author kay * @since 1.0 */ public class Test { public static void main(String[] arge) { ApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml"); Message message = context.getBean("message", Message.class); //本身寫的測試類 message.printMessage(); } }
由於ApplicationContext和FileSystemXmlApplicationContext代碼已經寫了,下面是運行時的時效圖,因此咱們直接從AbstractXmlApplicationContext開始。
FileSystemXmlApplicationContext運行時效圖
AbstractXmlApplicationContext.java
public AbstractXmlApplicationContext(ApplicationContext parent) { super(parent); }
在AbstractXmlApplicationContext中其實,也已經完成僅僅只是繼承一下。
AbstractRefreshableConfigApplicationContext.java
private String[] configLocations; public AbstractRefreshableConfigApplicationContext(ApplicationContext parent) { super(parent); } public void setConfigLocations(String... locations) { if (locations != null) { Assert.noNullElements(locations, "Config locations must not be null"); this.configLocations = new String[locations.length]; for (int i = 0; i < locations.length; i++) { this.configLocations[i] = resolvePath(locations[i]).trim(); } } else { this.configLocations = null; } }
而在AbstractRefreshableConfigApplicationContext中,除了繼承父類方法,還有就是FileSystemXmlApplicationContext中setConfigLocations方法的實現,setConfigLocations方法主要用於載入XML。
AbstractRefreshableApplicationContext.java
private DefaultListableBeanFactory beanFactory; public AbstractRefreshableApplicationContext(ApplicationContext parent) { super(parent); } protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); //容器開始初始化 beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); //容器的載入、解析和註冊 synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
在AbstractRefreshableApplicationContext類裏,核心部分都在實現refreshBeanFactory方法中獲得了實現。可是,卻不是在這裏進行的調用。
AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
最後在AbstractApplicationContext類中,進行了調用。經過同在AbstractApplicationContext中的refresh調用obtainFreshBeanFactory,進而調用子類中的refreshBeanFactory。至此,容器核心部分也就初始化完成。
上面對Ioc容器的初始化過程進行了分析,而這個初始化過程主要是在Ioc容器中創建BeanDefinition數據映射。但此過程並無出現對Bean依賴關係進行注入,接下來咱們對Bean依賴關係進行注入進行分析。
下面,咱們對DefaultListableBeanFactory進行分析。可是對代碼進行跟蹤,卻直接進入了DefaultListableBeanFactory的父類AbstractBeanFactory中。
這是依賴注入部分的時效圖
AbstractBeanFactory.java
//-------------------------------------------------------------------------------------------- // 這裏是對 BeanFactory 接口的實現,好比getBean接口方法 // 這些都是經過doGetBean來實現 // BeanFactory 接口 對應的5個實現,4個在這裏,還有一個由於其特殊性並非在這裏重載或者實現的 //-------------------------------------------------------------------------------------------- public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } //這個方法是個人程序調用的 public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); } public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException { return doGetBean(name, requiredType, args, false); } //這裏是實際觸發依賴注入的地方 protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { //指定名稱獲取被管理的Bean名稱,而且指定名稱中對容器的依賴 //若是是別名,將別名轉變爲Bean的名稱 final String beanName = transformedBeanName(name); Object bean; //先緩存取得的Bean以及處理建立過的單件模式的Bean //單態模式的Bean只能建立一次 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { //若是指定名稱的Bean在容器中已經存在,則直接返回 if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } //這裏完成FactoryBean的相關處理,對於FactoryBean,BeanFactory已經有所說起,在後面會詳細分析 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //緩存中若是已經存在建立的單態模式,由於循環而建立失敗,則拋出異常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //對容器中的BeanDefinition進行檢查,檢查可否在當前的BeanFactory中取得Bean. //若是在當前的工廠中取不到,則到父類的BeanFactory中去取 //若是在父類中取不到,則到父類的父類中取 BeanFactory parentBeanFactory = getParentBeanFactory(); //當前容器的父容器存在,且當前容器中不存在指名的Bean if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); //解析Bean的原始名 if (args != null) { //委派給父類容器查找,根據指定的名稱和顯示參數 return (T) parentBeanFactory.getBean(nameToLookup, args); } else { ///委派給父類容器查找,根據指定的名稱和類型 return parentBeanFactory.getBean(nameToLookup, requiredType); } } //建立的Bean是否須要進行驗證,通常不須要 if (!typeCheckOnly) { //向容器指定的Bean已被建立 markBeanAsCreated(beanName); } try { //根據Bean的名字獲取BeanDefinition final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); //獲取當前Bean的全部依賴的名稱 String[] dependsOn = mbd.getDependsOn(); 若是當前Bean有依賴Bean if (dependsOn != null) { for (String dependsOnBean : dependsOn) { if (isDependent(beanName, dependsOnBean)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'"); } //把被依賴的Bean註冊給當前依賴的Bean registerDependentBean(dependsOnBean, beanName); //觸發遞歸 getBean(dependsOnBean); } } //建立單態模式的Bean實例對象 if (mbd.isSingleton()) { //使用一個內部匿名類,建立Bean實例對象,而且註冊對所依賴的對象 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { //建立一個指定Bean實例對象,若是有父級繼承,則合併資對象 return createBean(beanName, mbd, args); } catch (BeansException ex) { //清除顯示容器單例模式Bean緩存中的實例對象 destroySingleton(beanName); throw ex; } } }); //獲取給定Bean實例對象 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // 判斷是不是原型模式 //原型模式會每次建立一個新的對象 Object prototypeInstance = null; try { //回調方法,註冊原型對象 beforePrototypeCreation(beanName); //建立指定Bean對象實例 prototypeInstance = createBean(beanName, mbd, args); } finally { //回調方法,Bean沒法再次建立 afterPrototypeCreation(beanName); } //獲取給定Bean的實例對象 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); //Bean定義資源中沒有配置生命週期範圍,則Bean不合法 if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { //這裏使用一個匿名類,獲取一個指定的生命週期範圍 Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); //獲取給定Bean的實例對象 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // 對建立的Bean進行類型檢查,若是沒有問題,就返回這個新建的Bean,這個Bean已經包含了依賴關係 if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type [" + ClassUtils.getQualifiedName(requiredType) + "]", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
從上面,能夠看出doGetBean,是依賴注入的實際入口,他定義了Bean的定義模式,單例模式(Singleton)和原型模式(Prototype),而依賴注入觸發的前提是BeanDefinition數據已經創建好的前提下。其實對於Ioc容器的使用,Spring提供了許多的參數配置,每個參數配置實際上表明瞭一個Ioc實現特性,而這些特性的實現不少都須要在依賴注入的過程當中或者對Bean進行生命週期管理的過程當中完成。Spring Ioc容器做爲一個產品,其真正的價值體如今一系列產品特徵上,而這些特徵都是以依賴反轉模式做爲核心,他們爲控制反轉提供了不少便利,從而實現了完整的Ioc容器。
下面是依賴注入的過程,下面咱們重點進行分析。
bean實例的建立和初始化:createBean
getBean是依賴注入的起點,以後就會調用createBean,createBean能夠生成須要的Bean以及對Bean進行初始化,但對createBean進行跟蹤,發現他在AbstractBeanFactory中僅僅是聲明,而具體實現是在AbstractAutowireCapableBeanFactory類裏。
AbstractBeanFactory.java
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException;
AbstractAutowireCapableBeanFactory.java
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; //判斷建立的Bean是否須要實例化,以及這個類是否須要經過類來裝載 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } try { //校驗和準備中的方法覆蓋 mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { //若是Bean配置了初始化前和後的處理器,則返回一個Bean對象 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } //建立Bean的入口 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } //Bean的真正建立位置 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { // 這個BearWrapper是用來封裝建立出來的Bean對象的 BeanWrapper instanceWrapper = null; // 若是是單態模式,就先把緩存中同名的Bean清除 if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } //建立Bean,由createBeanInstance來完成 if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); //調用PostProcessor後置處理器 synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } } //緩存單態模式的Bean對象,以防循環引用 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //匿名類,防止循環引用,可儘早的持有引用對象 addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } //初始化Bean的地方,依賴注入發生的地方 //exposedObject在初始化完成後,會做爲依賴注入完成後的Bean Object exposedObject = bean; try { //將Bean實例對象進行封裝,並將Bean定義的配置屬性賦值給實例對象 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { //初始化Bean exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } if (earlySingletonExposure) { //獲取指定名稱的單態模式對象 Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { //判斷註冊的實例化Bean和正在實例化的Bean是同一個 if (exposedObject == bean) { exposedObject = earlySingletonReference; } //當前Bean依賴其餘Bean,而且當發生循環引用時不容許建立新實例 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length); //獲取當前Bean的全部依賴 for (String dependentBean : dependentBeans) { //對依賴bean進行檢查 if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } //註冊完成依賴注入的Bean try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
在對doCreateBean的追蹤中咱們發現Bean的建立方法createBeanInstance與BeanDefinition的載入與解析方法populateBean方法是最爲重要的。由於控制反轉原理的實現就是在這兩個方法中實現的。
生成Bean中的對象:createBeanInstance
在createBeanInstance中生成了Bean所包含的Java對象,對象的生成有不少種不一樣的方法:工廠方法+反射,容器的autowire特性等等,這些生成方法都是由相關BeanDefinition來指定的。
AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { // 確認須要建立的Bean實例的類能夠實例化 Class<?> beanClass = resolveBeanClass(mbd, beanName); //這裏使用工廠方法對Bean進行實例化 if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } if (mbd.getFactoryMethodName() != null) { //工廠發生進行實例化 return instantiateUsingFactoryMethod(beanName, mbd, args); } //使用容器自動裝配方法進行實例化 boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { //配置自動裝配屬性,使用容器自動實例化 return autowireConstructor(beanName, mbd, null, null); } else { //無參構造方法實例化 return instantiateBean(beanName, mbd); } } //使用構造函數進行實例化 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { //使用容器自動裝配,調用構造方法實例化 return autowireConstructor(beanName, mbd, ctors, args); } //使用默認構造函數對Bean進行實例化 return instantiateBean(beanName, mbd); } /** * CGLIB是一個經常使用的字節碼生成器的類庫,他提供了一系列的API來提供生成和轉換Java的字節碼功能。 * 在Spring AOP中也使用CGLIB對Java的字節碼進行了加強。 */ private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy(); protected InstantiationStrategy getInstantiationStrategy() { return this.instantiationStrategy; } /** * 最多見的實例化過程instantiateBean * 使用默認的實例化策略對Bean進行實例化,默認的實例化策略是 * CglibSubclassingInstantiationStrategy,也就是用CGLIB來對Bean進行實例化 */ protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; //獲取系統的安全管理接口 if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { return getInstantiationStrategy().instantiate(mbd, beanName, parent); } }, getAccessControlContext()); } else { //實例化的對象封裝 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } }
咱們對CglibSubclassingInstantiationStrategy進行跟蹤,發現Spring中的CGLIB生成,是由SimpleInstantiationStrategy.instantiate方法來完成的,因此咱們就直接看SimpleInstantiationStrategy.instantiate。若是你對CGLIB有興趣,能夠仔細去研究,這裏由於篇幅,因此。。。
SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) { if (bd.getMethodOverrides().isEmpty()) { Constructor<?> constructorToUse; //指定構造器或者生成的對象工廠方法來對Bean進行實例化 synchronized (bd.constructorArgumentLock) { constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { final Class<?> clazz = bd.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (System.getSecurityManager() != null) { constructorToUse = AccessController.doPrivileged( new PrivilegedExceptionAction<Constructor<?>>() { @Override public Constructor<?> run() throws Exception { return clazz.getDeclaredConstructor((Class[]) null); } }); } else { constructorToUse = clazz.getDeclaredConstructor((Class[]) null); } bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Exception ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } //經過BeanUtils進行實例化,這個BeanUtils的實例化經過Constructor來完成 return BeanUtils.instantiateClass(constructorToUse); } else { //使用CGLIB來實例化對象 return instantiateWithMethodInjection(bd, beanName, owner); } }
屬性依賴注入實現:populateBean
Bean對象進行實例化之後。怎麼把這些Bean對象之間的依賴關係處理好,以完成整個依賴注入,而這裏就涉及到各類Bean對象依賴關係的處理過程了,而這些依賴關係都已經解析到了BeanDefinition。若是要仔細理解這個過程,咱們必須從前面提到的populateBean方法入手。
AbstractAutowireCapableBeanFactory.java
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { //這裏取得BeanDefinition中的property值 PropertyValues pvs = mbd.getPropertyValues(); //實例對象爲NULL if (bw == null) { //屬性不能爲空 if (!pvs.isEmpty()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { //實例對象爲NULL,屬性值也爲空,不需設置,直接返回 return; } } //在設置屬性以前調用Bean的PostProcessor後置處理器 boolean continueWithPropertyPopulation = true; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } if (!continueWithPropertyPopulation) { return; } //開始進行依賴注入過程,先處理autowire的注入 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); //根據Bean的名字或者類型自動裝配處理 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } //根據類型自動裝配注入 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } //檢查日期是否持有用於單態模式Bean關閉時的後置處理器 boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); //Bean實例對象沒有依賴,也沒有繼承 boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); if (hasInstAwareBpps || needsDepCheck) { //從實例對象中提取屬性描述符 PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; //使用BeanPostProcessor處理器處理屬性值 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { //對要配置的屬性進行依賴檢查 checkDependencies(beanName, mbd, filteredPds, pvs); } } //對屬性進行依賴注入 applyPropertyValues(beanName, mbd, bw, pvs); } protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { if (pvs == null || pvs.isEmpty()) { return; } //封裝屬性值 MutablePropertyValues mpvs = null; List<PropertyValue> original; if (System.getSecurityManager() != null) { if (bw instanceof BeanWrapperImpl) { //設置安全上下文,JDK安全機制 ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); } } if (pvs instanceof MutablePropertyValues) { mpvs = (MutablePropertyValues) pvs; //屬性值已經轉換 if (mpvs.isConverted()) { try { //爲實例化對象設置屬性值 bw.setPropertyValues(mpvs); return; } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } } //獲取屬性值對象的原始類型值 original = mpvs.getPropertyValueList(); } else { original = Arrays.asList(pvs.getPropertyValues()); } //獲取用戶自定義的類型轉換 TypeConverter converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } //建立一個Bean定義屬性值解析器,將Bean定義中的屬性值解析爲Bean實例對象 //的實際值 BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); //這裏爲解析值建立的一個副本,而後經過副本注入Bean List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size()); boolean resolveNecessary = false; for (PropertyValue pv : original) { //屬性值不須要轉換 if (pv.isConverted()) { deepCopy.add(pv); } //屬性值須要轉換 else { String propertyName = pv.getName(); //原始的屬性值,即轉換以前的屬性值 Object originalValue = pv.getValue(); //轉換屬性值,例如將引用轉換爲IoC容器中實例化對象引用 Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); //轉換以後的屬性值 Object convertedValue = resolvedValue; //屬性值是否能夠轉換 boolean convertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); if (convertible) { //使用用戶自定義的類型轉換器轉換屬性值 convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); } //存儲轉換後的屬性值,避免每次屬性注入時的轉換工做 if (resolvedValue == originalValue) { if (convertible) { //設置屬性轉換以後的值 pv.setConvertedValue(convertedValue); } deepCopy.add(pv); } //屬性是可轉換的,且屬性原始值是字符串類型,且屬性的原始類型值不是 //動態生成的字符串,且屬性的原始值不是集合或者數組類型 else if (convertible && originalValue instanceof TypedStringValue && !((TypedStringValue) originalValue).isDynamic() && !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { pv.setConvertedValue(convertedValue); deepCopy.add(pv); } else { resolveNecessary = true; //從新封裝屬性的值 deepCopy.add(new PropertyValue(pv, convertedValue)); } } } if (mpvs != null && !resolveNecessary) { mpvs.setConverted(); //標記屬性值已經轉換過 } // 這裏是依賴注入發生的地方 try { bw.setPropertyValues(new MutablePropertyValues(deepCopy)); } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } }
對代碼的分析,咱們知道當BeanDefinition完成載入和解析後,就進入依賴注入,這裏以屬性注入爲例。但真正依賴注入的地方倒是BeanWrapper接口。咱們對BeanWrapper接口進行跟蹤
他在doCreateBean中最早被定義,而後進入createBeanInstance
恩,最後,進入instantiateBean
最後獲得BeanWrapperImpl,就是說依賴注入是在BeanWrapperImpl裏完成的。可是以相同的方法對BeanWrapperImpl進行解析,最後發現AbstractNestablePropertyAccessor.setPropertyValue方法最爲重要。
而對BeanWrapper接口的跟蹤,咱們發現,BeanWrapper是一個組件接口,根據源碼分析,其做用是封裝主程序中的Bean實例。以此,咱們對applyPropertyValues從新分析,發現BeanDefinitionValueResolver.resolveValueIfNecessary方法是依賴注入的另外一個關鍵下面,咱們就對其進行分析。
屬性值的解析:resolveValueIfNecessary
BeanDefinitionValueResolver.java
public Object resolveValueIfNecessary(Object argName, Object value) { //對引用類型的屬性進行解析 if (value instanceof RuntimeBeanReference) { RuntimeBeanReference ref = (RuntimeBeanReference) value; //調用引用類型屬性的解析方法 return resolveReference(argName, ref); } //對屬性值是引用容器中另外一個Bean名稱的解析 else if (value instanceof RuntimeBeanNameReference) { String refName = ((RuntimeBeanNameReference) value).getBeanName(); refName = String.valueOf(doEvaluate(refName)); //從容器中獲取指定名稱的Bean if (!this.beanFactory.containsBean(refName)) { throw new BeanDefinitionStoreException( "Invalid bean name '" + refName + "' in bean reference for " + argName); } return refName; } //對Bean類型屬性的解析,主要是Bean中的內部類 else if (value instanceof BeanDefinitionHolder) { BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value; return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition()); } else if (value instanceof BeanDefinition) { BeanDefinition bd = (BeanDefinition) value; String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(bd); return resolveInnerBean(argName, innerBeanName, bd); } //對集合數組類型的屬性解析 else if (value instanceof ManagedArray) { ManagedArray array = (ManagedArray) value; Class<?> elementType = array.resolvedElementType; //獲取數組的類型 if (elementType == null) { String elementTypeName = array.getElementTypeName(); //獲取數組元素的類型 if (StringUtils.hasText(elementTypeName)) { try { //使用反射機制建立指定類型的對象 elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader()); array.resolvedElementType = elementType; } catch (Throwable ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error resolving array type for " + argName, ex); } } //沒有獲取到數組的類型,也沒有獲取到數組元素的類型,則直接設置數 //組的類型爲Object else { elementType = Object.class; } } //建立指定類型的數組 return resolveManagedArray(argName, (List<?>) value, elementType); } //解析list類型的屬性值 else if (value instanceof ManagedList) { return resolveManagedList(argName, (List<?>) value); } //解析set類型的屬性值 else if (value instanceof ManagedSet) { return resolveManagedSet(argName, (Set<?>) value); } //解析map類型的屬性值 else if (value instanceof ManagedMap) { return resolveManagedMap(argName, (Map<?, ?>) value); } //解析props類型的屬性值,props其實就是key和value均爲字符串的map else if (value instanceof ManagedProperties) { Properties original = (Properties) value; Properties copy = new Properties(); //建立一個拷貝,用於做爲解析後的返回值 for (Map.Entry<Object, Object> propEntry : original.entrySet()) { Object propKey = propEntry.getKey(); Object propValue = propEntry.getValue(); if (propKey instanceof TypedStringValue) { propKey = evaluate((TypedStringValue) propKey); } if (propValue instanceof TypedStringValue) { propValue = evaluate((TypedStringValue) propValue); } copy.put(propKey, propValue); } return copy; } //解析字符串類型的屬性值 else if (value instanceof TypedStringValue) { TypedStringValue typedStringValue = (TypedStringValue) value; Object valueObject = evaluate(typedStringValue); try { Class<?> resolvedTargetType = resolveTargetType(typedStringValue); //獲取屬性的目標類型 if (resolvedTargetType != null) { return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType); } //沒有獲取到屬性的目標對象,則按Object類型返回 else { return valueObject; } } catch (Throwable ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, ex); } } else { return evaluate(value); } } private Object resolveReference(Object argName, RuntimeBeanReference ref) { try { String refName = ref.getBeanName(); //獲取引用的Bean名稱 refName = String.valueOf(doEvaluate(refName)); //若是引用的對象在父類容器中,則從父類容器中獲取指定的引用對象 if (ref.isToParent()) { if (this.beanFactory.getParentBeanFactory() == null) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Can't resolve reference to bean '" + refName + "' in parent factory: no parent factory available"); } return this.beanFactory.getParentBeanFactory().getBean(refName); } //從當前的容器中獲取指定的引用Bean對象,若是指定的Bean沒有被實例化 //則會遞歸觸發引用Bean的初始化和依賴注入 else { Object bean = this.beanFactory.getBean(refName); //將當前實例化對象的依賴引用對象 this.beanFactory.registerDependentBean(refName, this.beanName); return bean; } } catch (BeansException ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); } }
屬性值得依賴注入:setPropertyValue
AbstractNestablePropertyAccessor的setPropertyValue有三個,但都指向最後一個:
AbstractNestablePropertyAccessor.java
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException { //PropertyTokenHolder主要保存屬性的名稱、路徑,以及集合的size等信息 String propertyName = tokens.canonicalName; String actualName = tokens.actualName; //keys是用來保存集合類型屬性的size if (tokens.keys != null) { //將屬性信息拷貝 PropertyTokenHolder getterTokens = new PropertyTokenHolder(); getterTokens.canonicalName = tokens.canonicalName; getterTokens.actualName = tokens.actualName; getterTokens.keys = new String[tokens.keys.length - 1]; System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1); Object propValue; try { //獲取屬性值,該方法內部使用JDK的內省(Introspector)機制,調用getter(readerMethod)方法,獲取屬性的值 propValue = getPropertyValue(getterTokens); } catch (NotReadablePropertyException ex) { throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, "Cannot access indexed value in property referenced " + "in indexed property path '" + propertyName + "'", ex); } String key = tokens.keys[tokens.keys.length - 1]; //獲取集合類型屬性的長度 if (propValue == null) { if (isAutoGrowNestedPaths()) { int lastKeyIndex = tokens.canonicalName.lastIndexOf('['); getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex); propValue = setDefaultValue(getterTokens); } else { throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, "Cannot access indexed value in property referenced " + "in indexed property path '" + propertyName + "': returned null"); } } //注入array類型的屬性值 if (propValue.getClass().isArray()) { PropertyHandler ph = getLocalPropertyHandler(actualName); //獲取屬性的描述符 Class<?> requiredType = propValue.getClass().getComponentType(); //獲取數組的類型 int arrayIndex = Integer.parseInt(key); //獲取數組的長度 Object oldValue = null; try { //獲取數組之前初始化的值 if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) { oldValue = Array.get(propValue, arrayIndex); } //將屬性的值賦值給數組中的元素 Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, ph.nested(tokens.keys.length)); int length = Array.getLength(propValue); if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) { Class<?> componentType = propValue.getClass().getComponentType(); Object newArray = Array.newInstance(componentType, arrayIndex + 1); System.arraycopy(propValue, 0, newArray, 0, length); setPropertyValue(actualName, newArray); propValue = getPropertyValue(actualName); } Array.set(propValue, arrayIndex, convertedValue); } catch (IndexOutOfBoundsException ex) { throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, "Invalid array index in property path '" + propertyName + "'", ex); } } //注入list類型的屬性值 else if (propValue instanceof List) { PropertyHandler ph = getPropertyHandler(actualName); Class<?> requiredType = ph.getCollectionType(tokens.keys.length); //獲取list集合的類型 List<Object> list = (List<Object>) propValue; int index = Integer.parseInt(key); //獲取list集合的size Object oldValue = null; if (isExtractOldValueForEditor() && index < list.size()) { oldValue = list.get(index); } Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, ph.nested(tokens.keys.length)); //獲取list解析後的屬性值 int size = list.size(); //爲list屬性賦值 //若是list的長度大於屬性值的長度,則多餘的元素賦值爲null if (index >= size && index < this.autoGrowCollectionLimit) { for (int i = size; i < index; i++) { try { list.add(null); } catch (NullPointerException ex) { throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, "Cannot set element with index " + index + " in List of size " + size + ", accessed using property path '" + propertyName + "': List does not support filling up gaps with null elements"); } } list.add(convertedValue); } else { try { list.set(index, convertedValue); } catch (IndexOutOfBoundsException ex) { throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, "Invalid list index in property path '" + propertyName + "'", ex); } } } /注入map類型的屬性值 else if (propValue instanceof Map) { PropertyHandler ph = getLocalPropertyHandler(actualName); Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length); //獲取map集合key的類型 Class<?> mapValueType = ph.getMapValueType(tokens.keys.length); //獲取map集合value的類型 Map<Object, Object> map = (Map<Object, Object>) propValue; TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType); Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor); //解析map類型屬性key值 Object oldValue = null; if (isExtractOldValueForEditor()) { oldValue = map.get(convertedMapKey); } //解析map類型屬性value值 Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), mapValueType, ph.nested(tokens.keys.length)); map.put(convertedMapKey, convertedMapValue); //將解析後的key和value值賦值給map集合屬性 } else { throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, "Property referenced in indexed property path '" + propertyName + "' is neither an array nor a List nor a Map; returned value was [" + propValue + "]"); } } //對非集合類型的屬性注入 else { PropertyHandler ph = getLocalPropertyHandler(actualName); if (ph == null || !ph.isWritable()) { if (pv.isOptional()) { if (logger.isDebugEnabled()) { logger.debug("Ignoring optional value for property '" + actualName + "' - property not found on bean class [" + getRootClass().getName() + "]"); } return; } else { throw createNotWritablePropertyException(propertyName); } } Object oldValue = null; try { Object originalValue = pv.getValue(); Object valueToApply = originalValue; if (!Boolean.FALSE.equals(pv.conversionNecessary)) { if (pv.isConverted()) { valueToApply = pv.getConvertedValue(); } else { if (isExtractOldValueForEditor() && ph.isReadable()) { try { oldValue = ph.getValue(); } catch (Exception ex) { if (ex instanceof PrivilegedActionException) { ex = ((PrivilegedActionException) ex).getException(); } if (logger.isDebugEnabled()) { logger.debug("Could not read previous value of property '" + this.nestedPath + propertyName + "'", ex); } } } valueToApply = convertForProperty( propertyName, oldValue, originalValue, ph.toTypeDescriptor()); } pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue); } ph.setValue(object, valueToApply); } catch (TypeMismatchException ex) { throw ex; } catch (InvocationTargetException ex) { PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); if (ex.getTargetException() instanceof ClassCastException) { throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException()); } else { Throwable cause = ex.getTargetException(); if (cause instanceof UndeclaredThrowableException) { cause = cause.getCause(); } throw new MethodInvocationException(propertyChangeEvent, cause); } } catch (Exception ex) { PropertyChangeEvent pce = new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); throw new MethodInvocationException(pce, ex); } } }
好了,自此,依賴注入部分就完了。
若是把Ioc容器比喻成一我的的話,Bean對象們就構成了他的骨架,依賴注入就是他的血肉,各類組件和支持則匯成了他的筋脈和皮膚,而各類特性則是他的靈魂。各類特性真正的使Spring Ioc有別於其餘Ioc框架,也成就了應用開發的豐富多彩,Spring Ioc 做爲一個產品,能夠說,他的各類特性纔是它真正的價值所在。
Spring Ioc的特性很是的多,瞭解了Spring Ioc容器整個運行原理後,按照相同思路分析這些特性相信也不是一件難事。若是讀者感興趣的話,也能夠按照相同的思路進行研究。這裏僅僅舉個例子:
例子:Bean的完整生命週期
Spring Bean的完整生命週期從建立Spring容器開始,直到最終Spring容器銷燬Bean,這其中包含了一系列關鍵點。
Bean的完整生命週期經歷了各類方法調用,這些方法能夠劃分爲如下幾類:
一、Bean自身的方法:這個包括了Bean自己調用的方法和經過配置文件中<bean>的init-method和destroy-method指定的方法
二、Bean級生命週期接口方法:這個包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean這些接口的方法
三、容器級生命週期接口方法:這個包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個接口實現,通常稱它們的實現類爲「後處理器」。
四、工廠後處理器接口方法:這個包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等很是有用的工廠後處理器接口的方法。工廠後處理器也是容器級的。在應用上下文裝配配置文件以後當即調用。
Spring Ioc容器的核心是BeanFactory和BeanDefinition。分別對應對象工廠和依賴配置的概念。雖然咱們一般使用的是ApplicationContext的實現類,但ApplicationContext只是封裝和擴展了BeanFactory的功能。XML的配置形式只是Spring依賴注入的一種經常使用形式而已,而AnnotationConfigApplicationContext配合Annotation註解和泛型,早已經提供了更簡易的配置方式,AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext則是實現無XML配置的核心接口,但不管你使用任何配置,最後都會映射到BeanDefinition。
其次,這裏特別要注意的仍是BeanDefinition, Bean在XML文件裏面的展示形式是<bean id="...">...</bean>,當這個節點被加載到內存中,就被抽象爲BeanDefinition了,在XML Bean節點中的那些關鍵字,在BeanDefinition中都有相對應的成員變量。如何把一個XML節點轉換成BeanDefinition,這個工做天然是由BeanDefinitionReader來完成的。Spring經過定義BeanDefinition來管理基於Spring的應用中的各類對象以及它們之間的相互依賴關係。BeanDefinition抽象了咱們對Bean的定義,是讓容器起做用的主要數據類型。咱們知道在計算機世界裏,全部的功能都是創建在經過數據對現實進行抽象的基礎上的。Ioc容器是用BeanDefinition來管理對象依賴關係的,對Ioc容器而言,BeanDefinition就是對控制反轉模式中管理的對象依賴關係的數據抽象,也是容器實現控制反轉的核心數據結構,有了他們容器才能發揮做用。
最後,其實IoC從原理上說是很是簡單的,就是把xml文件解析出來,而後放到內存的map裏,最後在內置容器裏管理bean。可是看IoC的源碼,卻發現其很是龐大,看着很是吃力。這是由於spring加入了不少特性和爲擴展性預留不少的接口,這些特性和擴展,造就了它無與倫比的功能以及將來無限的可能性,能夠說正是他們將技術的美學以最簡單的方法呈如今了人們面前,固然這也致使了他的複雜性。
Spring 的核心容器包括 Spring-Core、Spring-Context、Spring-beans、Spring-expression四個模塊。不知你察覺沒有, 筆者首先以BeanFactory容器爲切入點,囊括了Bean的建立、解析以及定義和依賴注入的實現,都在Spring-beans的核心部分中。而Spring-Context和Spring-Core也同樣,分別以ApplicationContext容器和Resource接口體系進行了囊括。Core模塊主要就是定義了訪問資源的方式,以及對於各類資源進行用統一的接口來抽象。而Context模塊的主要做用則是爲Bean對象提供、標識一個運行時環境,初始化BeanFactory並利用BeanFactory來將解析已經註冊的Bean進而進行依賴注入,保存Bean對象之間的依賴關係。Context的主要職責是將Core和Bean兩個模塊融合在一塊兒。而Spring-expression模塊,筆者由於時間不夠因此沒有寫,望你們見諒。
——水門(寫於2016年02月)