一文详解Spring是怎么读取配置Xml文件的

目录
  • Spring读取配置文件Document
  • Element
  • DocumentDefaultsDefinition

Spring读取配置文件Document

XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法中将Xml文件转换成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.根据Element root创建**BeanDefinitionParserDelegate**对象
		2.解析Xml文件头中的一些属性配置到 BeanDefinitionParserDelegate属性(DocumentDefaultsDefinition)defaults;
		**/
		this.delegate = createDelegate(getReaderContext(), root, parent);
		//根据root查询 xml文件的命名空间是不是public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
		if (this.delegate.isDefaultNamespace(root)) {
			//省略.....
		}
		//默认空实现 子类可以重写这个方法来处理自定义xml文件
		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
		//默认空实现 子类可以重写这个方法来处理自定义xml文件
		postProcessXml(root);

		this.delegate = parent;
	}

this.delegate = createDelegate(getReaderContext(), root, parent);里面调用 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文件中的一些命名空间的基本配置转换成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)) {
			//如果有父类,则以父类的为准,否则将返回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(文档的默认值定义)保存了 标准的Spring Xml文件中的 {@code beans} 层级的属性,这些属性是当前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

默认定义的标记接口,没有任何定义 ,只是单纯的标记一下;继承BeanMetadataElement类;通常具体的实现(例如DocumentDefaultsDefinition)是基于文档的默认值,例如在一个XML文档根标记级别来进行设置默认值

BeanMetadataElement

需要被实现的元数据接口,这个接口定义了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。 必须显示的使用”“标签明确地指定bean。
byName 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。
byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置 dependency-check=”objects”让Spring抛出异常。
constructor 与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。

解析完了一些xml中Element的默认属性,接下来就是解析Element中的子属性了 DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(root, this.delegate); 这个方法里我们主要看 delegate.parseCustomElement(ele);

	public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
		//获取命名空间
		String namespaceUri = getNamespaceURI(ele);
		//根据命名空间得到命名空间的处理类handler  如果是dubbo的uri 则返回的就是DubboNamespaceHandler
		//他们都继承自NamespaceHandlerSupport implements NamespaceHandler
		//里面有调用了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.根据Element的getLocalName()得到Element的name,然后根据这个name去NamespaceHandlerSupport中的一个属性为private final Map<String, BeanDefinitionParser> parsers ;中查找对应的解析器;这个解析器是什么时候被放到这个map里面的呢?TODO...
		//2.根据对应的解析器调用  .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的访问权限;

public class XmlReaderContext extends ReaderContext {
	//可以看到 方法权限是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中被创建

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		//创建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;
	}
	/**
	*如果没有具体的实现类,则创建 默认的实现类返回
	* 默认的实现类DefaultNamespaceHandlerResolver中的handlerMappingsLocation属性(Resource location to search for)=META-INF/spring.handlers
	*/
	protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
		return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
	}

②.创建后的XmlReaderContext被当做 BeanDefinitionParserDelegate 构造函数的参数来创建BeanDefinitionParserDelegate对象

protected void doRegisterBeanDefinitions(Element root) {
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);
		//省略.....
		}

到此这篇关于一文详解Spring是怎么读取配置Xml文件的的文章就介绍到这了,更多相关Spring Xml文件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot如何读取xml配置bean(@ImportResource)

    目录 读取xml配置bean(@ImportResource) 1.应用场景 2.spring-common.xml 3.SpringBoot读取xml 4.应用xml中的bean对象 5.Service类 6.测试 读取配置文件中的参数 1.打开eclipse开发工具软件 2.在项目中确保pom.xml文件已引用 3.在项目中的src/main/resource文件录目下 4.在application.properties配置文件中添加对应的参数 5.此时在项目启动的时候 6.在需要使用的配置

  • springboot 在xml里读取yml的配置信息的示例代码

    YML是什么 YAML (YAML Ain't a Markup Language)YAML不是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,一种专门用来写配置文件的语言.可用于如: Java,C/C++, Ruby, Python, Perl, C#, PHP等. 可以用<springProperty> 标签从Spring中显示属性 以下为在日志配置文件中读取的示例

  • spring mvc 读取xml文件数据库配置参数的方法

    本文主要介绍怎么通过属性注入与构造器注入实现把我们项目中要用到的数据库参数放到xml文件里面去,方便部署. spring mvc 4.2.6项目 SQL Server 2008数据库 本文介绍的主要使用ApplicationContext以及其实现类实现.主要用到的是ClassPathXmlApplicationContext. ClassPathXmlApplicationContext:从类路径ClassPath中寻找指定的XML配置文件,找到并装载 完成ApplicationContext

  • SpringBoot 如何读取pom.xml中的值

    目录 如何读取pom.xml中的值 xxx.properties读取pom.xml 读取xxx.properties文件 SpringBoot读取pom配置报错 报错原因 解决方法 如何读取pom.xml中的值 首先,Java代码中是无法直接读取pom.xml中的内容的,需要先把值转到xxx.properties中,再通过程序读取xxx.properties中对应的值. xxx.properties读取pom.xml 1.xxx.properties中 以pom.xml中的version标签为例

  • 一文详解Spring是怎么读取配置Xml文件的

    目录 Spring读取配置文件Document Element DocumentDefaultsDefinition Spring读取配置文件Document 在XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法中将Xml文件转换成Document对象; Document doc = doLoadDocument(inputSource, resource); El

  • 一文详解Spring Security的基本用法

    目录 1.引入依赖 2.用户名和密码在哪里设置 3.UserDetailsService接口详解 3.1JdbcDaoImpl实现类 3.2InMemoryUserDetailsManager实现类 3.3自定义实现类实现UserDetailsService接口 4.如何修改登录页面 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架, 提供了完善的认证机制和方法级的授权功能.是一款非常优秀的权限管理框架.它的核心是一组过滤器链,不同的功能经由不同的过滤器. 今天通

  • 一文详解Spring加载properties文件的方式

    目录 一.druid的资源配置管理 二.c3p0资源配置管理 三.加载properties文件 不加载系统属性 加载多个properties文件 加载所有properties文件 加载properties文件标准格式 从类路径或jar包中搜索并加载properties文件 spring第三方资源配置管理 DruidDataSource ComboPooledDataSource 一.druid的资源配置管理 导入druid的坐标: <dependency> <groupId>com

  • 一文详解Spring如何控制Bean注入的顺序

    目录 简介 构造方法依赖(推荐) @DependsOn(不推荐) BeanPostProcessor(不推荐) 简介 说明 本文介绍Spring如何控制Bean注入的顺序. 首先需要说明的是:在Bean上加@Order(xxx)是无法控制bean注入的顺序的! 控制bean的加载顺序的方法 1.构造方法依赖 2.@DependsOn 注解 3.BeanPostProcessor 扩展 Bean初始化顺序与类加载顺序基本一致:静态变量/语句块=> 实例变量或初始化语句块=> 构造方法=>

  • 一文详解Spring的Enablexxx注解使用实例

    目录 引言 @Enable 注解 @Import 注解 为什么要使用 @Import 注解呢 总结 引言 layout: post categories: Java title: 一文带你了解 Spring 的@Enablexxx 注解 tagline: by 子悠 tags: - 子悠 前面的文章给大家介绍 Spring 的重试机制的时候有提到过 Spring 有很多 @Enable 开头的注解,平时在使用的时候也没有注意过为什么会有这些注解,今天就给大家介绍一下. @Enable 注解 首先

  • 详解Spring Cloud Feign 熔断配置的一些小坑

    1.在使用feign做服务调用时,使用继承的方式调用服务,加入Hystrix的熔断处理fallback配置时,会报错,已解决. 2.使用feign默认配置,熔断不生效,已解决. 最近在做微服务的学习,发现在使用feign做服务调用时,使用继承的方式调用服务,加入Hystrix的熔断处理fallback配置时,会报错,代码如下: @RequestMapping("/demo/api") public interface HelloApi { @GetMapping("user/

  • 详解Spring Boot中PATCH上传文件的问题

    Spring Boot中上传multipart/form-data文件只能是Post提交,而不针对PATCH,这个问题花了作者26个小时才解决这个问题,最后不得不调试Spring源代码来解决这个问题. 需求:在网页中构建一个表单,其中包含一个文本输入字段和一个用于文件上载的输入.很简单.这是表单: <form id="data" method="PATCH" action="/f" > <input type="tex

  • 详解Spring MVC4 纯注解配置教程

    阅读本文需要又一定的sping基础,最起码要成功的运行过一个SpringMvc项目. 在传统的Spring项目中,我们要写一堆的XML文件.而这些XML文件格式要求又很严格,很不便于开发.而网上所谓的0配置,并不是纯粹的0配置,还是要写一些xml配置,只是用了几个@Service,@Controller注解而已. 在这里,我讲介绍一种新的配置方式,一行XML代码都不需要,什么web.xml,Application-context.xml,Beans.xml,统统去死吧! 首先建立一个Maven项

  • 一文详解Spring任务执行和调度(小结)

    一.概述 Spring框架分别使用TaskExecutor和TaskScheduler接口提供异步执行和任务调度的抽象.Spring还提供了这些接口的实现,这些接口支持线程池或将其委托给应用服务器环境中的CommonJ. 二.TaskExecutor Spring 2.0 开始引入的新的抽像.Executors 是线程池的Java 5名称.之所以称作是"执行器"是因为不能保证底层实现实际上是一个池;执行程序可以是单线程的,甚至是同步的.Spring的TaskExecutor接口与jav

  • 详解spring Boot Cli的配置和使用

    SpringBootCLI是一个命令行工具,可用于快速搭建基于spring的原型.它支持运行Groovy脚本,这也就意味着你可以使用类似Java的语法,但不用写很多的模板代码. Spring Boot不一定非要配合CLI使用,但它绝对是Spring应用取得进展的最快方式( 你咋不飞上天呢?) . 首先要下载分发包,下载地址如下 https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#getting-started

随机推荐