注:1.本文内容不是很细致,只能帮助大家了解个大概流程-_-||
2.方法里会删减无关的内容

spring beanDefinition加载,在方法obtainFreshBeanFactory中完成

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_spring


spring XML配置bean 如何使用resttemple spring xml bean加载顺序_java_02


refreshBeanFactory方法

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_xml_03

createBeanFactory:创建容器,会获取parent容器作为参数传入

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_递归_04


spring XML配置bean 如何使用resttemple spring xml bean加载顺序_spring_05

loadBeanDefinition:先创建beanDefinitionReader

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_xml_06


获取resource,也就是配置的xml文件

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_java_07


将resource读入,解析成document对象

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_spring_08


主要方法在这,传入doc节点,开始解析

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_xml_09


parseDefaultElement方法解析标签import、alias、bean、beans四种

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_spring_10

import解析

获取标签中resource的值,会根据location是否是绝对路径,走不同的分支。
将location解析为resource后,递归对该resource执行loadBeanDefinitions方法,

protected void importBeanDefinitionResource(Element ele) {
		String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
		location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
		boolean absoluteLocation = false;
		absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
		if (absoluteLocation) {
			int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
		}
		else {
				Resource relativeResource = getReaderContext().getResource().createRelative(location);
				if (relativeResource.exists()) {
					importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
					actualResources.add(relativeResource);
				}
				else {
					String baseLocation = getReaderContext().getResource().getURL().toString();
					importCount = getReaderContext().getReader().loadBeanDefinitions(
							StringUtils.applyRelativePath(baseLocation, location), actualResources);
				}
		}
		Resource[] actResArray = actualResources.toArray(new Resource[0]);
		getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
	}

alias解析

读取name、alias两个属性的值

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_绝对路径_11


1.如果alias和name相同,则aliasMap中移除这个alias。

2.根据alias查询aliasmap中是否已存在,已存在并且name相同则不再处理,已存在但name不同,则根据是否允许alias覆盖(allowAliasOverriding),来决定是否抛出异常。

3.检查name是否已经存在alias,存在则抛异常

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_spring_12

bean标签解析

将元素转为BeanDefinitionHolder,注册beanDefinition

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_xml_13


1.获取bean标签中的id、name属性的值

2.name不为空,则根据逗号、分号将name分割为数组

3.如果没有设置id,但是设置了name,会取第一个name作为beanName

4.检查beanName唯一性

5.parseBeanDefinitionElement方法会解析标签中的属性,并对beanDefinition进行赋值

6.beanName为空,则会产生一个,还会放入aliasmap。规则:class全路径名称+#+数字(从0开始自增,如果存在则继续下一个数字)

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		List<String> aliases = new ArrayList<>();
		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 (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		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);
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}
		return null;
	}

beans标签解析

递归过程,不再描述

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_xml_14


spring XML配置bean 如何使用resttemple spring xml bean加载顺序_spring_15


以上是parseDefaultElement解析过程,只解析标签beans、bean、alias、import四种其余例如aop标签解析,则在下面方法中。

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_spring_16


获取namespaceurl,也就是

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_绝对路径_17


根据namespaceurl找到相应的handler

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_绝对路径_18


再根据具体的标签名,找到parser

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_绝对路径_19


具体的解析过程都在parser的parse方法里,例如component-scan

先找base-package属性的值,

调用scan方法,先找出包下的所有类,再根据类上的注解@Component、@ManagedBean进行筛选,注册到容器中

spring XML配置bean 如何使用resttemple spring xml bean加载顺序_xml_20


其余标签解析也是这个流程,大家可以自行debug看看