溫故而知心。html
常說spring的控制反轉(依賴反轉),看看維基百科的解釋:java
若是合做對象的引用或依賴關係的管理要由具體對象來完成,會致使代碼的高度耦合和可測試性下降,這對複雜的面向對象系統的設計使很是不利的。node
在面向對象系統中,對象封裝了數據和對數據的處理,對象的依賴關係經常體如今對數據和方法的依賴上。這些依賴關係能夠經過把對象的依賴注入交給框架或者IoC容器來完成,這種從具體對象手中交出控制的作法是很是有價值的,它能夠在解耦代碼的同時提升代碼的可測試性。算法
做爲IoC容器,也須要爲它的具體實現指定基本的功能規範,這個功能規範的設計表現爲接口類BeanFactory,它體現了Spring爲提供給用戶使用的IoC容器所設定的最基本功能規範。spring
Spring經過定義BeanDefinition來管理基於Spring的應用中的各類對象以及它們之間的相互依賴關係。BeanDefinition抽象了咱們對Bean的定義,是讓容器起做用的主要數據類型。IoC容器是用來管理對象依賴關係的,對IoC容器來講,BeanDefinition就是對依賴反轉模式中管理的對象依賴關係的數據抽象,也是容器實現依賴反轉功能的核心數據結構,依賴反轉功能都是圍繞對這個BeanDefinition的處理上完成的。編程
弄清楚這兩種重要容器之間的區別和聯繫,意味着咱們具有辨別容器系列中不一樣容器產品的能力。還有一個好處就是,若是須要定製特定功能的容器實現,也能比較方便的在容器系列中找到一款恰當的產品做爲參考。設計模式
從前面咱們知道,BeanFactory定義了IoC容器的基本功能規範,全部,下面咱們就從BeanFactory這個最基本的容器定義來進入Spring的IoC容器體系,去了解IoC容器的實現原理。緩存
BeanFactory定義了IoC容器的最基本形式,而且提供了IoC容器所應該遵照的最基本的服務契約。在Spring的代碼中,BeanFactory只是一個接口類,並無給出容器的具體實現,具體類能夠上前面的截圖,如DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等均可以當作是容器的附加了某種功能的具體實現,也就是容器體系中的具體容器產品。數據結構
用戶使用容器時,可使用轉義符「&」來獲得FactoryBean自己,用來區別經過容器獲取FactoryBean產生的對象和獲取FactoryBean自己。(舉例說明:myJndiObject是一個FactoryBean,那麼使用&myJndiObject獲得的是FactoryBean,而不是myJndiObject這個FactoryBean產生出來的對象)。app
注意:理解上面這段話須要很好的區分FactoryBean和BeanFactory這兩個再spring中使用頻率很高的類,他們在拼寫上很是類似,
BeanFactory與FactoryBean的區別見《Spring之1:的BeanFactory和FactoryBean》
BeanFactory的繼承提現,AutowireCapableBeanFactory-->AbstractAutowireCapableBeanFactory-->DefaultListableBeanFactory-->XmlBeanFactory IoC容器的實現系列。
從這個容器系列的最底層實現XmlBeanFactory開始,這個容器的實現與咱們在Spring應用中用到的那些上下文對比,有一個明顯的特色,它只提供了最基本的IoC容器的功能。從它的名字中能夠看出,這個IoC容器能夠讀取以XML形式定義的BeanDefinition。能夠認爲XmlBeanFactory實現是IoC容器的基本形式,而各類ApplicationContext的實現是IoC容器的高級形式。
XmlBeanFactory的源碼:
public class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); } public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); } }
XmlBeanFactory是一個與XML相關的BeanFactory,也就是說它能夠讀取以XML文件方式定義的BeanDefinition的一個IoC容器。對這些XML文件定義信息的處理由其定義的XmlBeanDefinitionReader對象,有了這個reader對象,那些以XML的方式定義的BeanDefinition就有了處理的地方。咱們能夠看到,對這些XML形式的信息的處理其實是由這個XmlBeanDefinitionReader來完成的。
參考XmlBeanFactory的實現,咱們能夠以編程的方式使用DefaultListableBeanFactory。
例如:編程方式使用IoC容器:更多的見《Spring之A:Spring Bean動態註冊、刪除》
ApplicationContext ctx = SpringApplication.run(Application.class, args); // 獲取BeanFactory DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) ctx .getAutowireCapableBeanFactory(); // 建立bean信息. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TestService.class); beanDefinitionBuilder.addPropertyValue("name", "張三"); // 動態註冊bean. defaultListableBeanFactory.registerBeanDefinition("testService", beanDefinitionBuilder.getBeanDefinition());
在IoC容器實現中的那些關鍵的類(好比Resource、DefaultListableBeanFactory以及BeanDefinitionReader)之間的相互關係,能夠看出其功能解耦的做用。在使用IoC容器時,須要以下幾個步驟:
ApplicationContext
在Spring中系統已經爲用戶提供了許多已經定義好的容器實現,而不須要開發人員事必躬親。相比那些簡單拓展BeanFactory的基本IoC容器,其中ApplicationContext是推薦的BeanFactory,由於除了能提供容器的基本功能外,還爲用戶提供了更多的附加服務。
見《Spring之3:BeanFactory、ApplicationContext、ApplicationContextAware區別》
IoC容器的初始化包括BeanDefinition的Resource定位、載入和註冊這三個基本的過程。在《Spring之2:Spring Bean動態註冊、刪除》中,咱們演示了這三個過程的實現。Spring在實現中把這三個過程分開並使用不一樣的模塊來完成的,這樣可讓用戶更加靈活地對這三個過程進行剪裁和擴展,定義出最適合本身的IoC容器的初始化過程。
1、Resource定位。BeanDefinition的資源定位有resourceLoader經過統一的Resource接口來完成,這個Resource對各類形式的BeanDefinition的使用提供了統一接口。對於這些BeanDefinition的存在形式,相信不陌生,如:
FileSystemResource、ClassPathResource。這個過程相似於容器尋找數據的過程,就像用水桶裝水要把水找到同樣。
2、第二個關鍵的部分是BeanDefinition的載入,該載入過程把用戶定義好的Bean表示成IoC容器內部的數據結構,而這個容器內部的數據結構就是BeanDefinition。簡單說,BeanDefinition其實是POJO對象在IoC容器中的抽象,這個BeanDefinition定義了一系列的數據來使得IoC容器可以方便地對POJO對象也就是Spring的Bean進行管理。即BeanDefinition就是Spring的領域對象。
3、第三個過程是向IoC容器註冊這些BeanDefinition的過程。這個過程是經過調用BeanDefinitionRegistry接口的實現來完成的,這個註冊過程把載入過程當中解析獲得的BeanDefinition向IoC容器進行註冊。能夠看到,在IoC容器內部,是經過使用一個HashMap來持有BeanDefinition數據的。
回到咱們常用的ApplicationContext上來,例如FileSystemXmlApplicationContext、ClassPathXmlApplicationContext以及XmlWebApplicationContext等。簡單地從這些類的名字上分析,能夠清楚地看到它們能夠提供哪些不一樣的Resource讀入功能,
FileSystemXmlApplicationContext的類層級關係:
FileSystemXmlApplicationContext extends AbstractXmlApplicationContext,具有了ResourceLoacer讀入Resource定義的BeanDefinition的能力,由於AbstractXmlApplicationContext的基類是DefaultResourceLoader(AbstractApplicationContext extends DefaultResourceLoader)。FileSystemXmlApplicationContext是一個支持XML定義BeanDefinition的ApplicationContext,而且能夠指定以文件形式的BeanDefinition的讀入,這些文件可使用文件路徑和URL定義來表示。這個在單元測試時,很是有用。
FileSystemXmlApplicationContext.java源碼
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext { public FileSystemXmlApplicationContext() { } public FileSystemXmlApplicationContext(ApplicationContext parent) { super(parent); } /** * 這個構造函數的configLocation包含的是BeanDefinition所在的文件路徑 */ public FileSystemXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } /** * 這個構造函數容許configLocation包含多個BeanDefinition的文件路徑 */ public FileSystemXmlApplicationContext(String... configLocations) throws BeansException { this(configLocations, true, null); } /** * 這個構造函數在容許configLocation包含多個BeanDefinition的文件路徑的同時,還容許指定本身的雙親IoC容器 */ public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException { this(configLocations, true, parent); } public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException { this(configLocations, refresh, null); } /** * 在對象的初始化過程當中,調用refresh函數載入BeanDefinition,這個refresh啓動了BeanDefinition的載入過程,咱們會在下面進行詳細分析 */ public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } } /** * 這是應用於文件系統中Resource的實現,經過構造一個FileSystemResource來獲得一個在文件系統中定位的BeanDefinition * 這個getResourceByPath是在BeanDefinitionReader的loadBeanDefinition中被調用的。 * loadBeanDefinition採用了模板模式,具體的定位實現其實是由各個子類完成的 */ @Override protected Resource getResourceByPath(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); } }
構造函數中經過refresh()中啓動IoC容器的初始化,這個refresh方法很是重要,也是咱們之後分析容器初始化過程的一個重要入口。
FileSystemXmlApplicationContext的基類AbstractRefreshableApplicationContext,重點看看AbstractRefreshableApplicationContext的refreshBeanFactory()方法,
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //IoC容器是DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); //加載BeanDefinition loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
在初始化FileSystemXmlApplicationContext的過程當中,經過IoC容器的初始化refresh來啓動整個應用,使用IoC容器的是DefaultListableBeanFactory。具體資源加載是在XmlBeanDefinitionReader讀入BeanDefinition時完成,在XmlBeanDefinitionReader的基類AbstractBeanDefinitionReader中可看到這個載入過程的具體實現。
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
對載入過程的啓動,能夠在AbstractRefreshableApplicationContext的loadBeanDefinition方法中看到
AbstractRefreshableApplicationContext對容器的初始化
@Override protected final void refreshBeanFactory() throws BeansException { //判斷,若是已經創建了BeanFactory,則銷燬並關閉該BeanFactory if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } //這裏是建立並設置特有的DefaultListableBeanFactor的地方。 //同時調用loadBeanDefinition在載入BeanDefinition的信息。 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); } }
建立DefaultListableBeanFactory實例
/** *這就是上下文中建立DefaultListableBeanFactory的地方,而getInternalParentBeanFactory()的具體實現能夠參看AbstractApplicationCtontext中的實現,會根據容器已有的雙親IoC容器的信息來生成DefaultListableBeanFactory的雙親IoC容器 */ protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); }
getInernalParentBeanFactory,會根據容器已有的雙親IoC容器的信息來生成DefaultListableBeanFactory的雙親IoC容器
protected BeanFactory getInternalParentBeanFactory() { return (getParent() instanceof ConfigurableApplicationContext) ? ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent(); }
loadBeanDefinition()是一個抽象函數把具體實現委託給子類來完成,容許載入的方式有不少種:
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException;
對於IoC容器來講,BeanDefinition的載入過程至關於把咱們定義的BeanDefinition在IoC容器中轉化成一個Spring內部表示的數據結構的過程。IoC容器對Bean的管理和依賴注入功能的實現,是經過對其持有的BeanDefinition進行各類相關的操做來完成的。這些BeanDefinition數據在IoC容器裏經過一個HashMap來保持和維護,固然這只是一種比較簡單的維護方式,若是你以爲須要提供IoC容器的性能和容量,徹底能夠本身作一些擴展。
能夠從DefaultListableBeanFactory入手看看IoC容器是怎樣完成BeanDefinition載入的。
/** * 在對象的初始化過程當中,調用refresh函數載入BeanDefinition,這個refresh啓動了BeanDefinition的載入過程,咱們會在下面進行詳細分析 */ public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); //這裏調用容器的refresh,是載入BeanDefinition的入口。 if (refresh) { refresh(); } }
refresh方法,對容器啓動來講,很是重要。它詳細描述了整個ApplicationContext的初始化過程,好比BeanFactory的更新,messagesource和postprocessor的註冊,等等。這裏看起來更像是對ApplicationContext進行初始化的模板或執行大綱,這個執行過程爲IoC容器Bean的什麼週期管理提供了條件。IoC容器的refresh過程以下:
AbstractApplicationContext.refresh()
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //這裏是在子類中啓動refreshBeanFactory()的地方,在obtainFreshBeanFactory()裏調用refreshBeanFactory() ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
咱們進入到AbstractRefreshableApplicationContext的refreshBeanFactory()方法中,在這個方法裏建立了BeanFactory。
@Override protected final void refreshBeanFactory() throws BeansException { //判斷,若是已經創建了BeanFactory,則銷燬並關閉該BeanFactory if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } //這裏是建立並設置特有的DefaultListableBeanFactor的地方。 //同時調用loadBeanDefinition在載入BeanDefinition的信息。 try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); //啓動對BeanDefinition的載入。 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
這裏調用的loadBeanDefinitions(beanFactory)是一個抽象方法,那麼實際載入過程是在哪裏發送的呢?
看看AbstractXmlApplicationContext中的實現:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. //建立XmlBeanDefinitionReader,並經過回調設置到BeanFactory中取 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); //這裏設置XmlBeanDefinitionReader,爲XmlBeanDefinitionReader配置ResourceLoader,由於DefaultResourceLoader是父類,全部this能夠直接被使用。 beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. //這是啓動Bean定義信息載入的過程 initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
接着看loadBeanDefinitions(XmlBeanDefinitionReader reader)方法
AbstractXmlApplicationContext.loadBeanDefinitions(XmlBeanDefinitionReader reader)方法:首先獲得BeanDefinition信息的Resource定位,而後直接調用XmlBeanDefinitionReader讀取具體的載入過程是委託給BeanDefinitionReader來完成的。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //首先獲得BeanDefinition信息的Resource定位 Resource[] configResources = getConfigResources(); if (configResources != null) { //調用BeanDefinitionReader讀取BeanDefinition信息 reader.loadBeanDefinitions(configResources); } //下面相似,只是這裏是多個Resource場景 String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
經過上面實現原理分析,咱們能夠看到,在初始化FileSystemXmlApplicationContext的過程當中,是經過調用IoC容器的refresh來啓動整個BeanDefinition的載入過程的,這個初始化是經過定義的XmlBeanDefinitionReader來完成的。
同時,咱們也知道實際使用的IoC容器是DefaultListableBeanFactory,具體的Resource載入在XmlBeanDefinitionReader讀入BeanDefinition時實現。
由於Spring能夠對應不一樣形式的BeanDefinition。上面講的是XML方式定義場景,因此須要使用XmlBeanDefinitionReader。
AbstractBeanDefinitionReader.loadBeanDefinitions(Resource... resources)
@Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { //若是Resource爲空,則中止BeanDefinition的載入。 //而後啓動載入BeanDefinition的過程,這個過程會遍歷整個Resource集合所包含的BeanDefnition信息。 Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter; }
這裏調用的是loadBeanDefinitions(Resource resource)方法,然而這個方法在AbstractBeanDefinitionReader接口裏沒有實現,是一個接口方法,具體的實如今XmlBeanDefinitionReader中,在讀取器中,須要獲得表明XML文件的Resource,由於這個Resource對象封裝了對XML文件的IO操做,因此讀取器能夠在打開IO流後獲得XML的文件對象。有了這個Document對象後,就能夠按照Spring的Bean定義規則來對這個XML的文檔樹進行解析了,這個解析時交給BeanDefinitionParserDelegate來完成的,看起來實現脈絡很清楚。具體實現代碼:
XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource)和loadBeanDefinitions(EncodedResource encodedResource):
//這裏是調用的入口 public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } //這裏是載入XML形式的BeanDefinition的地方。 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!"); } //這裏獲得XML文件,並獲得IO的InputSource準備進行讀取。 try { 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(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } //具體的讀取過程能夠在doLoadBeanDefinitions方法中找到。 //這是從特定的XML文件中實際載入BeanDefinition的地方。 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { 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 { //這裏取得XML文件的Document對象,這個解析過程是有documentLoader完成的, //這個documentLoader是DefaultDocmentLoader,在定義documentLoader的地方建立 return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, getValidationModeForResource(resource), isNamespaceAware()); }
DefaultDocumentLoader.loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware)方法:
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); }
下面看看Spring的BeanDefinition是怎樣按照Spring的Bean語義要求進行解析並轉化爲容器內部數據結構的,這個過程是在registerBeanDefinitions(doc, resource)完成的。具體過程是有BeanDefinitionDocumentReader來完成的,這個registerBeanDefinitions(doc, resource)還對載入的Bean的數量進行了統計。具體代碼:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //這裏獲得BeanDefinitionDocumentReader來對xml的BeanDefinition進行解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); //具體解析過程在這個registerBeanDefinitions中完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
BeanDefinition的載入包括兩部分,
首先經過調用XML的解析器獲得document對象,但這些document對象並無按照Spring的Bean規則進行解析。在完成通用的XML解析之後,纔是按照Spring的Bean規則進行解析的地方,按照Spring的Bean規則進行解析的過程是在documentReader中實現的。
而後再完成BeanDefinition的處理,處理的結果由BeanDefinitionHolder對象持有。這個BeanDefinitionHolder除了持有BeanDefinition對象外,還持有了其餘與BeanDefinition的使用相關的信息,好比Bean的名字、別名集合等。具體的Spring BeanDefinition的解析是在BeanDefinitionParserDelegate中完成的。這裏包含了各類Spring Bean定義規則的處理。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { //這裏取得在<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; 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); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. 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; }
咱們看到了對Bean元素進行解析的過程,也就是BeanDefinition依據XML的<bean>定義被建立的過程。這個BeanDefinition能夠當作是<bean>定義的抽象。這個數據對象裏封裝的數據大多數是與<bean>定義相關的,也有不少就是咱們在定義Bean時看到的那些Spring標記,好比init-method、destroy-method、factory-method,等等,這個BeanDefinition數據類型是很是重要的,它封裝了不少基本數據。有了這些基本數據,IoC容器才能對Bean配置進行處理,才能實現相應容器特性。
看起來很熟悉吧,beanClass、description、lazyInit這些屬性都是在配置Bean時常常碰到的,原來都跑道這裏了。BeanDefinition是IoC容器體系中很是重要的核心數據結構。
對BeanDefinition的元素的處理
在對其處理的過程當中能夠看到對Bean定義的相關處理,好比對元素attribute值的處理,對元素屬性值的處理,對構造函數設置的處理等等。
BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean):
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); //這裏只讀取定義的<bean>中設置的class名字,而後載入到BeanDefinition中取,只是坐個記錄,並不涉及對象的實例化過程,對象的實例化其實是在依賴注入時完成的。 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); } //這裏生成須要的BeanDefinition對象,爲Bean定義信息的載入作準備。 AbstractBeanDefinition bd = createBeanDefinition(className, parent); //這裏對當前的Bean元素進行屬性解析,並設置description的信息 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //從名字能夠清楚地看到,這裏是對各類<bean>元素的信息進行解析的地方。 parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析<bean>的構造函數設置 parseConstructorArgElements(ele, bd); //解析<bean>的property設置 parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } //下面這些異常時咱們在配置bean出問題時常常能夠看到的,原來是在這裏拋出的, 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; }
上面是具體生成BeanDefinition的地方。
舉例對property進行解析的例子來完成對整個BeanDefinition載入過程的分析,仍是在類BeanDefinitionParserDelegate的代碼中,它對BeanDefinition中定義一層一層地進行解析,好比從屬性元素集合到具體的每個屬性元素,而後纔是對具體的屬性值的處理。根據解析結果,對這些屬性值的處理會封裝成PropertyValue對象並設置到BeanDefinition對象中去,
//這裏對指定bean元素的property子元素集合進行解析 public void parsePropertyElements(Element beanEle, BeanDefinition bd) { //遍歷全部bean元素下定義的property元素 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { //在上面判斷是property元素後對該property元素進行解析的過程。 parsePropertyElement((Element) node, bd); } } } public void parsePropertyElement(Element ele, BeanDefinition bd) { //這裏取得property的名字 String propertyName = ele.getAttribute(NAME_ATTRIBUTE); 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值的地方,返回的對象對應對bean定義的property屬性,設置解析結果,這個解析結果會封裝到PropertyValue對象中,而後設置的解析結果,這個解析結果會封裝到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(); } } //這裏取得property元素的值,也許是一個list或其餘 public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // Should only have one child element: ref, value, list, etc. 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)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } }
上面是對property子元素的解析過程,Array、List、Set、Map、Prop等各類元素都會在這裏進行解析,生成對應的數據對象,parseArrayElement、parseListElment、parseSetElement、parseMapElement、parsePropElement對應不一樣類型的數據解析。
通過這樣逐層地解析,咱們在XML文件中定義的BeanDefinition就被整個給載入到了IoC容器中,並在容器中創建了數據映射。在IoC容器中創建了對應的數據結構,或者說能夠當作是POJO對象在IoC容器中的映像,這些數據結構能夠以AbstractBeanDefinition爲入口,讓IoC容器執行索引、查詢和操做。通過上面的載入過程,IoC容器大體完成了管理Bean對象的數據準備工做。如今接着看最重要的依賴注入過程。
上面已經分析了BeanDefinition在IoC容器中載入和解析的過程。在這些動做完成之後,用戶定義的BeanDefinition信息已經在IoC容器內創建起了本身的數據結構以及相應的數據表示,但此時這些數據還不能讓IoC容器直接使用,須要在IoC容器中對這些BeanDefinition數據進行註冊。這個註冊爲IoC容器提供更友好的使用方式。
DefaultListableBeanFactory中,是經過一個HashMap來持有載入的BeanDefinition的,這個HashMap的定義在DefaultListableBeanFactory能夠看到。以下:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { //... /** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256); //... }
BeanDefinition註冊的實現,
DefaultListableBeanFactory 繼承了BeanDefinitionRegistry的接口,這個接口的實現完成了BeanDefinition向容器的註冊。這個註冊過程不復雜,就是把解析獲得的BeanDefinition設置到hashMap中取。須要注意的是,若是遇到同名的BeanDefinition的狀況,進行處理的時候須要依據allowBeanDefinitionOverriding的配置來完成。
//--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface //--------------------------------------------------------------------- @Override 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"); 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); //檢查是否是有相同名字的BeanDefinition已經在IoC容器中註冊了,若是有相同名字的BeanDefinition,但又不容許覆蓋,那麼拋出異常。 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()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE 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); } //這是正常註冊BeanDefinition的過程,把Bean的名字存入到BeanDefinitionNames的同時,把beanName做爲Map的key, //把beanDefinition做爲value存入到IoC容器持有的beanDefinitionMap中去。 else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) 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 { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
完成了BeanDefinition的註冊,就完成了IoC容器的初始化過程。此時,在咱們使用的IoC容器DefaultListableBeanFactory中已經創建了整個Bean的配置信息,並且這些BeanDefinition已經能夠被容器使用了,他們均可以在beanDefinitionMap裏檢索和使用。
容器的做用就是對這些信息進行處理和維護。這些信息是容器創建依賴反轉的基礎,有了這些基礎數據,下面看在IoC容器中,依賴注入時怎樣完成的。
假設當前IoC容器已經載入了用戶定義的Bean信息,如今能夠開始分析依賴注入的原理。
首先,依賴注入的過程是用戶在第一次向IoC容器索要Bean時觸發的(調用BeanFactory的getBean方法時),固然也有例外,也就是咱們能夠在BeanDefinition信息中經過控制lazy-init屬性來讓容器完成對Bean的預實例化。
爲了瞭解這個依賴注入過程,咱們從DefaultListableBeanFactory的基類AbstractBeanFactory入手去看看getBean的實現。
依賴注入入口
//--------------------------------------------------------------------- // Implementation of BeanFactory interface //這裏是對BeanFactory接口的實現,好比getBean接口方法 //這些getBean接口方法最終是經過調用doGetBean來實現的 //--------------------------------------------------------------------- @Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } @Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } @Override public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); } @Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } @Override public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); } //這裏是實際去取bean的地方,也是觸發依賴注入發送的地方。 protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. //從緩存中去取,處理已經被建立過的單件模式的bean,對這種bean的請求不須要重複地建立。 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { 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 + "'"); } } //這裏的getObjectForBeanInstance完成的是FactoryBean的相關處理, //以取得FactoryBean的生產結果,咱們在前面介紹過BeanFactory和FactoryBean的區別 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. //這裏對IoC容器裏的BeanDefinition是否存在進行檢查,檢查是否能在當前的BeanFactory中渠道咱們須要的Bean。 //若是在當前的工廠中取不到,則到雙親BeanFactory中去取;若是當前的雙親工廠取不到,那就順着雙親BeanFactory鏈一直向上查找。 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } // if (!typeCheckOnly) { markBeanAsCreated(beanName); } //這裏根據bean的名字取得BeanDefinition try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. //取當前bean的全部依賴bean,這樣會觸發getBean的遞歸調用,直至取到一個沒有任何依賴的bean位置 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } registerDependentBean(dep, beanName); getBean(dep); } } //這裏建立Singleton bean實例,經過調用createBean方法,這裏有一個回調函數getObject,會在getSingleton中去調用ObjectFactory的createBean //下面會進入到createBean中去進行詳細分析 // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //這裏是建立prototype bean的地方 else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); 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 = 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; } } // Check if required type matches the type of the actual bean instance. //這裏對建立出來的bean進行類型檢查,若是沒有問題,就返回這個新建立出來的bean,這個bean已經包含了依賴關係的bean if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { 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; }
這個就是依賴注入的入口,在這裏觸發了依賴注入,而依賴注入的發生是在容器中的BeanDefinition數據已經創建好的前提下進行的。
「程序=數據+算法」:前面的BeanDefinition就是數據。
怎樣依賴注入
雖然依賴注入過程不涉及複雜的算法問題,但這個過程也不簡單,由於Spring提供了許多參數配置,每個參數配置實際上表明瞭一個IoC容器的實現特性,這些特性的實現不少都須要在依賴注入的過程當中或者對Bean進行生命週期管理的過程當中來完成。IoC容器裏是經過HashMap來存儲的,但這不是IoC容器的所有。Spring IoC容器的價值體如今一系列相關的產品特性上,這些產品特性以依賴反轉模式的實現爲核心,爲用戶更好地使用依賴反轉提供便利,從而實現一個完整的IoC容器產品。
依賴注入的詳細過程
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; // Make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved Class // which cannot be stored in the shared merged bean definition. //這裏判斷須要建立的bean是否能夠實例化,這個類是否能夠經過類裝載器來載入。 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. try { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. 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; } //咱們接着到doCreateBean中去看看bean是怎樣生成的: protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { // Instantiate the bean. //這個BeanWrapper是用來持有建立出來的bean對象的。 BeanWrapper instanceWrapper = null; //若是是singleton,先把緩存中的同名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); mbd.resolvedTargetType = beanType; // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. 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); } }); } // Initialize the bean instance. //這裏是對bean的初始化,依賴注入每每在這裏發生,這個exposedObject在初始化處理完成之後會返回做爲依賴注入完成後的bean Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { 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) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length); for (String dependentBean : dependentBeans) { 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."); } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
與依賴注入關係特別密切的方法有createBeanInstance和populateBean,下面分別到這兩個方法裏看看發生了什麼。
createBeanInstance:生成bean所包含的java對象,這個對象的生成有不少不一樣的方式,能夠經過工廠方法生成,也能夠經過容器的autowire特性生成,這些生成方式都是由相關的BeanDefinition來指定的。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { // Make sure bean class is actually resolved at this point. //確認須要建立的bean實例的類能夠實例化 Class<?> beanClass = resolveBeanClass(mbd, beanName); 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()); } //這裏使用工廠方法對bean進行實例化。 if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... 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); } } // Need to determine the constructor... //使用構造函數進行實例化 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // No special handling: simply use no-arg constructor. //使用默認的構造函數對bean進行實例化 return instantiateBean(beanName, mbd); } //咱們看看最多見的實例化過程instantiateBean protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { //使用默認的實例化的策略對bean進行實例化,默認的實例化策略是CglibSubclassingInstantiationStrategy,也就是用cglib來對bean進行實例化。 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); } }
在這裏用到了cglib對Bean進行實例化,cglib是一個經常使用的字節碼生成器的類庫,它提供了一系列的API來提供java的字節碼生成和轉換功能。
在實例化Bean對象生成的基礎上,咱們看看Spring是怎樣對這些對象進行處理的,也就是Bean對象生成後,怎樣把這些Bean對象的依賴關係設置好,完成整個依賴注入過程。這些依賴關係處理的依據就是已經解析獲得的BeanDefinition。
AbstractAutowireCapableBeanFactory.populateBean中的實現代碼:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { //這裏取得在BeanDefinition中設置的property值,這些property來自對BeanDefinition的解析。 PropertyValues pvs = mbd.getPropertyValues(); if (bw == null) { if (!pvs.isEmpty()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { // Skip property population phase for null instance. return; } } // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the // state of the bean before properties are set. This can be used, for example, // to support styles of field injection. 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); // Add property values based on autowire by name if applicable. //這裏是對autowire注入的處理,根據bean的名字或者type進行autowire的過程。 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); 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; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); } } //對屬性進行注入。 applyPropertyValues(beanName, mbd, bw, pvs); } //接着上面到applyPropertyValues看看具體對屬性進行解析而後注入的過程: 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) { ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); } } if (pvs instanceof MutablePropertyValues) { mpvs = (MutablePropertyValues) pvs; if (mpvs.isConverted()) { // Shortcut: use the pre-converted values as-is. 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; } //注意這個BeanDefinitionValueResolver對BeanDefinition的解析時在這個valueResolver中完成的。 BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); // Create a deep copy, resolving any references for values. //這裏爲解析值建立一個靠背,拷貝的數據將會被注入到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(); 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); } // Possibly store converted value in merged bean definition, // in order to avoid re-conversion for every created bean instance. 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(); } // Set our (possibly massaged) deep copy. //這裏是依賴注入發生的地方,會在BeanWrapperImpl中完成。 try { bw.setPropertyValues(new MutablePropertyValues(deepCopy)); } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } }
這裏經過BeanDefinitionValueResolver來對BeanDefinition進行解析,而後注入到property中。下面到BeanDefinitionValueResolver中看看解析過程的實現,以對Bean reference進行resolve的爲例子,看看整個resolve的過程:
private Object resolveReference(Object argName, RuntimeBeanReference ref) { try { //從runtimeBeanReference取得reference的名字,這個runtimeBeanReference是在載入BeanDefinition時根據配置生成的。 String refName = ref.getBeanName(); refName = String.valueOf(doEvaluate(refName)); //若是ref是在雙親IoC容器中,那就到雙親IoC容器中去取。 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); } //在當前IoC容器中去取bean,這裏會觸發一個getBean的過程,若是依賴注入沒有發生, //這裏會觸發相應的依賴注入的發生。 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); } }
在Bean的建立和對象依賴注入的過程當中,須要依據BeanDefinition中的信息來遞歸地完成依賴注入。從上面能夠看到幾個遞歸的過程,這些遞歸都是以getBean爲入口的。
這樣,根據依賴關係,一層一層的完成Bean的建立和注入,直到最後完成當前Bean的建立,有了這個頂層Bean的建立和對它的屬性依賴注入的完成,也意味着和當前Bean相關的整個依賴鏈的注入完成。
在Bean建立和依賴注入完成之後,在IoC容器中創建一系列靠依賴關係聯繫起來的Bean,這個Bean已經不是簡單的Java對象了。這個Bean系列創建完成之後,經過IoC容器的相關接口方法,就能夠很是方便地讓上層應用使用了。
經過設置Bean的lazy-init屬性來控制預實例化的過程,這個預實例化在初始化容器時完成Bean的依賴注入,毫無疑問,這種容器的使用方式會對容器初始化的性能有一些影響,但卻可以提升應用第一次取得Bean的性能。由於應用在第一次取得Bean時,依賴注入已經結束了,應用能夠取到現成的Bean。
再回到DefaultListableBeanFactory這個級別容器的preInstantiateSingletons。這個方法對單例Bean完成預實例化,這個預實例化的完成巧妙地委託給容器來實現。若是須要預實例化,那麼就直接在這裏採用getBean去觸發依賴注入,與正常依賴注入的觸發相比,只有觸發的時間和場合不一樣。在這裏,依賴注入發生在容器refresh的過程當中,而不像通常的依賴注是發生在IoC容器初始化完成之後,第一次向容器getBean時。
AbstractApplicationContext.refresh()
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //這裏是對lazy-init屬性進行處理的地方。 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { //... } }
再接着到finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)中看一下具體的處理過程:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // Register a default embedded value resolver if no bean post-processor // (such as a PropertyPlaceholderConfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(new StringValueResolver() { @Override public String resolveStringValue(String strVal) { return getEnvironment().resolvePlaceholders(strVal); } }); } // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes. beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. //調用的是BeanFactory的preInstantiateSingletons,這個方法是有DefaultListableBeanFactory實現的。 beanFactory.preInstantiateSingletons(); } //在DefaultListableBeanFactory中的preInstantiateSingletons是這樣的: public void preInstantiateSingletons() throws BeansException { if (this.logger.isDebugEnabled()) { this.logger.debug("Pre-instantiating singletons in " + this); } //這裏就開始去getBean了,也就是去觸發bean的依賴注入。 //若是沒有設置lazy-init,那麼這個依賴注入發生在容器初始化結束之後,第一次向容器getBean時,若是設置了lazy-init,那麼依賴注入發生在容器初始化的過程當中, //會對BeanDefinitionMap中全部的bean進行依賴注入, 這樣在初始化過程結束之後,當向容器getBean獲得的就是已經準備好的Bean,不須要進行依賴注入。 for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } //... }
根據上面得知,能夠經過lazy-init屬性來對整個IoC容器的初始化和依賴注入過程作一些簡單的控制。
BeanPostProcessor是使用IoC容器時常常遇到的一個特性,這個bean是一個後知處理器是一個監聽器,它能夠監聽容器觸發的事件。把它像IoC容器註冊之後,使得容器中管理的Bean具有了接收IoC容器事件回調的能力。
BeanPostProcessor接口有兩個方法,這些都是圍繞着Bean定義的init-method方法調用。
並且,這兩個回調的觸發都是和容器管理Bean的生命週期相關的。這兩個回調方法的參數都是同樣的,分別是Bean的實例化對象和Bean的名字,
postProcessBeforeInitialization是在populateBean完成以後調用的,
postProcessAfterInitialization是在populateBean方法中的initializeBean調用。
在Spring中,相對於顯示的依賴管理方式,IoC容器還提供了自動依賴裝配的方式,爲應用使用容器提供更大方便。
在自動裝配中,不須要對Bean屬性作顯示依賴關係申明,只須要配置好autowire(自動依賴裝配)屬性,IoC容器會根據這個屬性的配置,使用反射自動的查找屬性的類型或名字,而後基於屬性的類型或名字來自動匹配IoC容器中的Bean,從而自動的完成依賴注入。