原文出自:http://cmsblogs.comjava
獲取 Document 對象後,會根據該對象和 Resource 資源對象調用 registerBeanDefinitions()
方法,開始註冊 BeanDefinitions 之旅。以下:node
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
首先調用 createBeanDefinitionDocumentReader()
方法實例化 BeanDefinitionDocumentReader 對象,而後獲取統計前 BeanDefinition 的個數,最後調用 registerBeanDefinitions()
註冊 BeanDefinition。spring
實例化 BeanDefinitionDocumentReader 對象方法以下:post
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); }
註冊 BeanDefinition 的方法 registerBeanDefinitions()
是在接口 BeanDefinitionDocumentReader 中定義,以下:測試
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException;
從給定的 Document 對象中解析定義的 BeanDefinition 並將他們註冊到註冊表中。方法接收兩個參數,待解析的 Document 對象,以及解析器的當前上下文,包括目標註冊表和被解析的資源。其中 readerContext 是根據 Resource 來建立的,以下:this
public XmlReaderContext createReaderContext(Resource resource) { return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, getNamespaceHandlerResolver()); }
DefaultBeanDefinitionDocumentReader 對該方法提供了實現:spa
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
調用 doRegisterBeanDefinitions()
開啓註冊 BeanDefinition 之旅。debug
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { // 處理 profile 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)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } // 解析前處理 preProcessXml(root); // 解析 parseBeanDefinitions(root, this.delegate); // 解析後處理 postProcessXml(root); this.delegate = parent; }
程序首先處理 profile屬性,profile主要用於咱們切換環境,好比切換開發、測試、生產環境,很是方便。而後調用 parseBeanDefinitions()
進行解析動做,不過在該方法以前以後分別調用 preProcessXml()
和 postProcessXml()
方法來進行前、後處理,目前這兩個方法都是空實現,交由子類來實現。code
protected void preProcessXml(Element root) { } protected void postProcessXml(Element root) { }
parseBeanDefinitions()
定義以下:對象
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); 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); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
最終解析動做落地在兩個方法處:parseDefaultElement(ele, delegate)
和 delegate.parseCustomElement(root)
。咱們知道在 Spring 有兩種 Bean 聲明方式:
<bean id="studentService" class="org.springframework.core.StudentService"/>
<tx:annotation-driven>
兩種方式的讀取和解析都存在較大的差別,因此採用不一樣的解析方法,若是根節點或者子節點採用默認命名空間的話,則調用 parseDefaultElement()
進行解析,不然調用 delegate.parseCustomElement()
方法進行自定義解析。
至此,doLoadBeanDefinitions()
中作的三件事情已經所有分析完畢,下面將對 Bean 的解析過程作詳細分析說明。