一文詳解Spring是怎么讀取配置Xml文件的
Spring讀取配置文件Document
在XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法中將Xml文件轉(zhuǎn)換成Document對(duì)象; Document doc = doLoadDocument(inputSource, resource);

Element
org.w3c.dom.Element 是一個(gè)接口 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();
//注冊(cè)BeanDefinitions
doRegisterBeanDefinitions(root);
}在DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root)中
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
/**
1.根據(jù)Element root創(chuàng)建**BeanDefinitionParserDelegate**對(duì)象
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)) {
//省略.....
}
//默認(rèn)空實(shí)現(xiàn) 子類可以重寫這個(gè)方法來處理自定義xml文件
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
//默認(rèn)空實(shí)現(xiàn) 子類可以重寫這個(gè)方法來處理自定義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 是一個(gè)DocumentDefaultsDefinition對(duì)象;
populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
this.readerContext.fireDefaultsRegistered(this.defaults);
}BeanDefinitionParserDelegate.populateDefaults方法主要是講xml文件中的一些命名空間的基本配置轉(zhuǎn)換成DocumentDefaultsDefinition 對(duì)象; 例如
<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對(duì)象
protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
//查看xml文件中默認(rèn)的default-lazy-init 值;(如果xml沒有顯示配置 則它的值為 default)懶加載的默認(rèn)值
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(文檔的默認(rèn)值定義)保存了 標(biāo)準(zhǔn)的Spring Xml文件中的 {@code beans} 層級(jí)的屬性,這些屬性是當(dāng)前Xml配置中的默認(rèn)全局屬性值,例如 { @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 |
|---|
默認(rèn)定義的標(biāo)記接口,沒有任何定義 ,只是單純的標(biāo)記一下;繼承BeanMetadataElement類;通常具體的實(shí)現(xiàn)(例如DocumentDefaultsDefinition)是基于文檔的默認(rèn)值,例如在一個(gè)XML文檔根標(biāo)記級(jí)別來進(jìn)行設(shè)置默認(rèn)值
BeanMetadataElement
需要被實(shí)現(xiàn)的元數(shù)據(jù)接口,這個(gè)接口定義了Object getSource()方法,返回一個(gè)配置源對(duì)象
public class DocumentDefaultsDefinition implements DefaultsDefinition {
//初始化懶加載
private String lazyInit;
//
private String merge;
// 自動(dòng)裝載的類型
private String autowire;
//
private String dependencyCheck;
private String autowireCandidates;
//初始化方法
private String initMethod;
//銷毀方法
private String destroyMethod;
//返回配置源對(duì)象
private Object source;
//省略 get set ......
}default-autowire和autowire的可選值:
| 可選值 | 功能說明 |
|---|---|
| no | 默認(rèn)不使用autowiring。 必須顯示的使用”“標(biāo)簽明確地指定bean。 |
| byName | 根據(jù)屬性名自動(dòng)裝配。此選項(xiàng)將檢查容器并根據(jù)名字查找與屬性完全一致的bean,并將其與屬性自動(dòng)裝配。 |
| byType | 如果容器中存在一個(gè)與指定屬性類型相同的bean,那么將與該屬性自動(dòng)裝配。如果存在多個(gè)該類型的bean,那么將會(huì)拋出異常,并指出不能使用byType方式進(jìn)行自動(dòng)裝配。若沒有找到相匹配的bean,則什么事都不發(fā)生,屬性也不會(huì)被設(shè)置。如果你不希望這樣,那么可以通過設(shè)置 dependency-check=”objects”讓Spring拋出異常。 |
| constructor | 與byType的方式類似,不同之處在于它應(yīng)用于構(gòu)造器參數(shù)。如果在容器中沒有找到與構(gòu)造器參數(shù)類型一致的bean,那么將會(huì)拋出異常。 |
| autodetect | 通過bean類的自省機(jī)制(introspection)來決定是使用constructor還是byType方式進(jìn)行自動(dòng)裝配。如果發(fā)現(xiàn)默認(rèn)的構(gòu)造器,那么將使用byType方式。 |
解析完了一些xml中Element的默認(rèn)屬性,接下來就是解析Element中的子屬性了 DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(root, this.delegate); 這個(gè)方法里我們主要看 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ù)這個(gè)name去NamespaceHandlerSupport中的一個(gè)屬性為private final Map<String, BeanDefinitionParser> parsers ;中查找對(duì)應(yīng)的解析器;這個(gè)解析器是什么時(shí)候被放到這個(gè)map里面的呢?TODO...
//2.根據(jù)對(duì)應(yīng)的解析器調(diào)用 .parse(element,parserContext)進(jìn)行解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}讓我們來單獨(dú)解析一下 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri) 首先了解一下 this.readerContext是BeanDefinitionParserDelegate中的一個(gè)屬性 private final XmlReaderContext readerContext; ##XmlReaderContext
繼承了ReaderContext類,并且提供了 對(duì)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是什么時(shí)候被賦值的呢?我們順著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;
}
/**
*如果沒有具體的實(shí)現(xiàn)類,則創(chuàng)建 默認(rèn)的實(shí)現(xiàn)類返回
* 默認(rèn)的實(shí)現(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對(duì)象
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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot+URule實(shí)現(xiàn)可視化規(guī)則引擎的方法示例
規(guī)則引擎其實(shí)是一種組件,它可以嵌入到程序當(dāng)中,將程序復(fù)雜的判斷規(guī)則從業(yè)務(wù)代碼中剝離出來,使得程序只需要關(guān)心自己的業(yè)務(wù),而不需要去進(jìn)行復(fù)雜的邏輯判斷,本文給大家介紹了SpringBoot+URule實(shí)現(xiàn)可視化規(guī)則引擎的方法示例,需要的朋友可以參考下2024-12-12
Spring Cloud如何使用Feign構(gòu)造多參數(shù)的請(qǐng)求
這篇文章主要介紹了Spring Cloud如何使用Feign構(gòu)造多參數(shù)的請(qǐng)求,以GET以及POST方法的請(qǐng)求為例進(jìn)行講解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
基于resty orm的ActiveRecord操作數(shù)據(jù)指南
這篇文章主要為大家介紹了基于resty orm的ActiveRecord操作數(shù)據(jù)指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
spring?boot對(duì)敏感信息進(jìn)行加解密的項(xiàng)目實(shí)現(xiàn)
本文主要介紹了spring?boot對(duì)敏感信息進(jìn)行加解密的項(xiàng)目實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
關(guān)于Spring中@Transactional事務(wù)回滾的注意事項(xiàng)
這篇文章主要介紹了關(guān)于Spring中@Transactional事務(wù)回滾的注意事項(xiàng),回滾(Rollback)指的是程序或數(shù)據(jù)處理錯(cuò)誤,將程序或數(shù)據(jù)恢復(fù)到上一次正確狀態(tài)的行為?;貪L包括程序回滾和數(shù)據(jù)回滾等類型,需要的朋友可以參考下2023-05-05
mybatis的test坑及解決(不等于‘‘ 且 不等于0)
這篇文章主要介紹了mybatis的test坑及解決(不等于‘‘ 且 不等于0),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
解決Springboot項(xiàng)目報(bào)錯(cuò):java:錯(cuò)誤:不支持發(fā)行版本?17
這篇文章主要給大家介紹了關(guān)于解決Springboot項(xiàng)目報(bào)錯(cuò):java:錯(cuò)誤:不支持發(fā)行版本17的相關(guān)資料,這個(gè)錯(cuò)誤意味著你的Spring Boot項(xiàng)目正在使用Java 17這個(gè)版本,但是你的項(xiàng)目中未配置正確的Java版本,需要的朋友可以參考下2023-08-08
jd-easyflow中inclusive的用法示例小結(jié)
文章介紹了在jd-easyflow中使用inclusive進(jìn)行條件分支配置的方法,當(dāng)conditionType設(shè)置為inclusive時(shí),所有條件分支都會(huì)被評(píng)估,而不僅僅是一個(gè)條件滿足就終止,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-11-11

