一文詳解Spring是怎么讀取配置Xml文件的
Spring讀取配置文件Document
在XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)
方法中將Xml文件轉(zhuǎn)換成Document對象; Document doc = doLoadDocument(inputSource, resource);
Element
org.w3c.dom.Element 是一個接口 public interface Element extends Node
Spring中DefaultBeanDefinitionDocumentReader中
@Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); // 從Document中獲取Element Element root = doc.getDocumentElement(); //注冊BeanDefinitions doRegisterBeanDefinitions(root); }
在DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root)
中
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; /** 1.根據(jù)Element root創(chuàng)建**BeanDefinitionParserDelegate**對象 2.解析Xml文件頭中的一些屬性配置到 BeanDefinitionParserDelegate屬性(DocumentDefaultsDefinition)defaults; **/ this.delegate = createDelegate(getReaderContext(), root, parent); //根據(jù)root查詢 xml文件的命名空間是不是public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans"; if (this.delegate.isDefaultNamespace(root)) { //省略..... } //默認空實現(xiàn) 子類可以重寫這個方法來處理自定義xml文件 preProcessXml(root); parseBeanDefinitions(root, this.delegate); //默認空實現(xiàn) 子類可以重寫這個方法來處理自定義xml文件 postProcessXml(root); this.delegate = parent; }
this.delegate = createDelegate(getReaderContext(), root, parent);
里面調(diào)用 BeanDefinitionParserDelegate.initDefaults方法 1.初始化屬性值 private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
2. TODO...
public void initDefaults(Element root, BeanDefinitionParserDelegate parent) { // this.defaults 是一個DocumentDefaultsDefinition對象; populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root); this.readerContext.fireDefaultsRegistered(this.defaults); }
BeanDefinitionParserDelegate.populateDefaults方法主要是講xml文件中的一些命名空間的基本配置轉(zhuǎn)換成DocumentDefaultsDefinition 對象; 例如
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd" default-autowire="byName" default-lazy-init="false" default-dependency-check="all" >
//parentDefaults是父類的DocumentDefaultsDefinition對象 protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) { //查看xml文件中默認的default-lazy-init 值;(如果xml沒有顯示配置 則它的值為 default)懶加載的默認值 String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { //如果有父類,則以父類的為準(zhǔn),否則將返回false。 lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE); } defaults.setLazyInit(lazyInit); //default-autowire-candidates String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE); if (DEFAULT_VALUE.equals(merge)) { // Potentially inherited from outer <beans> sections, otherwise falling back to false. merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE); } defaults.setMerge(merge); //default-autowire String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE); if (DEFAULT_VALUE.equals(autowire)) { // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'. autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE); } defaults.setAutowire(autowire); // Don't fall back to parentDefaults for dependency-check as it's no longer supported in // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it. defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE)); if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) { defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates()); } if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) { defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setInitMethod(parentDefaults.getInitMethod()); } if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) { defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setDestroyMethod(parentDefaults.getDestroyMethod()); } //這里是??? defaults.setSource(this.readerContext.extractSource(root)); }
DocumentDefaultsDefinition
DocumentDefaultsDefinition(文檔的默認值定義)保存了 標(biāo)準(zhǔn)的Spring Xml文件中的 {@code beans} 層級的屬性,這些屬性是當(dāng)前Xml配置中的默認全局屬性值,例如 { @code default-lazy-init },{ @code default-autowire },等等。
例如:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd" default-autowire="byName" default-lazy-init="false" default-dependency-check="all" >
###DefaultsDefinition |
---|
默認定義的標(biāo)記接口,沒有任何定義 ,只是單純的標(biāo)記一下;繼承BeanMetadataElement類;通常具體的實現(xiàn)(例如DocumentDefaultsDefinition)是基于文檔的默認值,例如在一個XML文檔根標(biāo)記級別來進行設(shè)置默認值
BeanMetadataElement
需要被實現(xiàn)的元數(shù)據(jù)接口,這個接口定義了Object getSource()方法,返回一個配置源對象
public class DocumentDefaultsDefinition implements DefaultsDefinition { //初始化懶加載 private String lazyInit; // private String merge; // 自動裝載的類型 private String autowire; // private String dependencyCheck; private String autowireCandidates; //初始化方法 private String initMethod; //銷毀方法 private String destroyMethod; //返回配置源對象 private Object source; //省略 get set ...... }
default-autowire和autowire的可選值:
可選值 | 功能說明 |
---|---|
no | 默認不使用autowiring。 必須顯示的使用”“標(biāo)簽明確地指定bean。 |
byName | 根據(jù)屬性名自動裝配。此選項將檢查容器并根據(jù)名字查找與屬性完全一致的bean,并將其與屬性自動裝配。 |
byType | 如果容器中存在一個與指定屬性類型相同的bean,那么將與該屬性自動裝配。如果存在多個該類型的bean,那么將會拋出異常,并指出不能使用byType方式進行自動裝配。若沒有找到相匹配的bean,則什么事都不發(fā)生,屬性也不會被設(shè)置。如果你不希望這樣,那么可以通過設(shè)置 dependency-check=”objects”讓Spring拋出異常。 |
constructor | 與byType的方式類似,不同之處在于它應(yīng)用于構(gòu)造器參數(shù)。如果在容器中沒有找到與構(gòu)造器參數(shù)類型一致的bean,那么將會拋出異常。 |
autodetect | 通過bean類的自省機制(introspection)來決定是使用constructor還是byType方式進行自動裝配。如果發(fā)現(xiàn)默認的構(gòu)造器,那么將使用byType方式。 |
解析完了一些xml中Element的默認屬性,接下來就是解析Element中的子屬性了 DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(root, this.delegate);
這個方法里我們主要看 delegate.parseCustomElement(ele);
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { //獲取命名空間 String namespaceUri = getNamespaceURI(ele); //根據(jù)命名空間得到命名空間的處理類handler 如果是dubbo的uri 則返回的就是DubboNamespaceHandler //他們都繼承自NamespaceHandlerSupport implements NamespaceHandler //里面有調(diào)用了hander的init()... NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } //1.根據(jù)Element的getLocalName()得到Element的name,然后根據(jù)這個name去NamespaceHandlerSupport中的一個屬性為private final Map<String, BeanDefinitionParser> parsers ;中查找對應(yīng)的解析器;這個解析器是什么時候被放到這個map里面的呢?TODO... //2.根據(jù)對應(yīng)的解析器調(diào)用 .parse(element,parserContext)進行解析 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
讓我們來單獨解析一下 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)
首先了解一下 this.readerContext
是BeanDefinitionParserDelegate中的一個屬性 private final XmlReaderContext readerContext;
##XmlReaderContext
繼承了ReaderContext類,并且提供了 對XmlBeanDefinitionReader 和 NamespaceHandlerResolver的訪問權(quán)限;
public class XmlReaderContext extends ReaderContext { //可以看到 方法權(quán)限是private 的 private final XmlBeanDefinitionReader reader; private final NamespaceHandlerResolver namespaceHandlerResolver; public XmlReaderContext( Resource resource, ProblemReporter problemReporter, ReaderEventListener eventListener, SourceExtractor sourceExtractor, XmlBeanDefinitionReader reader, NamespaceHandlerResolver namespaceHandlerResolver) { super(resource, problemReporter, eventListener, sourceExtractor); this.reader = reader; this.namespaceHandlerResolver = namespaceHandlerResolver; } //但是提供了一些訪問的方法 public final XmlBeanDefinitionReader getReader() { return this.reader; } public final BeanDefinitionRegistry getRegistry() { return this.reader.getRegistry(); } public final ResourceLoader getResourceLoader() { return this.reader.getResourceLoader(); } public final ClassLoader getBeanClassLoader() { return this.reader.getBeanClassLoader(); } public final Environment getEnvironment() { return this.reader.getEnvironment(); } public final NamespaceHandlerResolver getNamespaceHandlerResolver() { return this.namespaceHandlerResolver; } public String generateBeanName(BeanDefinition beanDefinition) { return this.reader.getBeanNameGenerator().generateBeanName(beanDefinition, getRegistry()); } public String registerWithGeneratedName(BeanDefinition beanDefinition) { String generatedName = generateBeanName(beanDefinition); getRegistry().registerBeanDefinition(generatedName, beanDefinition); return generatedName; } public Document readDocumentFromString(String documentContent) { InputSource is = new InputSource(new StringReader(documentContent)); try { return this.reader.doLoadDocument(is, getResource()); } catch (Exception ex) { throw new BeanDefinitionStoreException("Failed to read XML document", ex); } }
1.那XmlReaderContext是什么時候被賦值的呢?我們順著XmlReaderContext了解一下 ①. XmlBeanDefinitionReader.registerBeanDefinitions中被創(chuàng)建
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); //創(chuàng)建XmlReaderContext,然后賦值給BeanDefinitionDocumentReader中readerContext屬性中 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } public XmlReaderContext createReaderContext(Resource resource) { //this 最后就是 XmlReaderContext中的XmlBeanDefinitionReader屬性 return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, getNamespaceHandlerResolver()); } public NamespaceHandlerResolver getNamespaceHandlerResolver() { if (this.namespaceHandlerResolver == null) { this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); } return this.namespaceHandlerResolver; } /** *如果沒有具體的實現(xiàn)類,則創(chuàng)建 默認的實現(xiàn)類返回 * 默認的實現(xiàn)類DefaultNamespaceHandlerResolver中的handlerMappingsLocation屬性(Resource location to search for)=META-INF/spring.handlers */ protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() { return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader()); }
②.創(chuàng)建后的XmlReaderContext被當(dāng)做 BeanDefinitionParserDelegate 構(gòu)造函數(shù)的參數(shù)來創(chuàng)建BeanDefinitionParserDelegate對象
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); //省略..... }
到此這篇關(guān)于一文詳解Spring是怎么讀取配置Xml文件的的文章就介紹到這了,更多相關(guān)Spring Xml文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
idea maven 構(gòu)建本地jar包及pom文件的過程
這篇文章主要介紹了idea maven 構(gòu)建本地jar包及pom文件的過程,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11springboot結(jié)合全局異常處理實現(xiàn)登錄注冊驗證
這篇文章主要介紹了springboot結(jié)合全局異常處理實現(xiàn)登錄注冊驗證,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05Mybatis多表關(guān)聯(lián)查詢的實現(xiàn)(DEMO)
本節(jié)要實現(xiàn)的是多表關(guān)聯(lián)查詢的簡單demo。場景是根據(jù)id查詢某商品分類信息,并展示該分類下的商品列表,需要的朋友可以參考下2017-02-02微服務(wù)如何通過feign.RequestInterceptor傳遞參數(shù)
這篇文章主要介紹了微服務(wù)如何通過feign.RequestInterceptor傳遞參數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03springboot整合Mybatis-plus的實現(xiàn)
這篇文章主要介紹了springboot整合Mybatis-plus的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09java?使用BeanFactory實現(xiàn)service與dao層解耦合詳解
這篇文章主要介紹了java?使用BeanFactory實現(xiàn)service與dao層解耦合詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12