栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring-IOC加载流程(1.setConfigLocations方法)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring-IOC加载流程(1.setConfigLocations方法)

#博学谷IT学习技术支持#

上一节我们大体了解了一下Spring-IOC执行的大致流程,没看过的小伙伴可以通过链接查看

Spring ioc执行流程(粗讲)

小伙伴们看完后,应该还很茫然。不过不要着急,接下来我们开始逐步分析。

首先,根据上节使用ClassPathXmlApplicationContext类来加载xml配置文件,我们跟进源码。

ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		//设置父级,这里parent为null
		super(parent);
		//这里进行介质并设置配置文件的路径,就是上面的 classpath:applicationContext.xml
		setConfigLocations(configLocations);
		//是否执行refresh操作,这里默认为true
		if (refresh) {
			refresh();
		}
	}

本节主要讲解setConfigLocation()方法

跟进setConfigLocations()方法,会到resolvePath()方法

this.configLocations[i] = resolvePath(locations[i]).trim();

继续跟进resolvePath()方法

protected String resolvePath(String path) {
	return getEnvironment().resolveRequiredPlaceholders(path);
}

getEnvironment()方法
getEnvironment()方法创建了StandardEnvironment类,调用StandardEnvironment父类AbstractEnvironment的构造方法

public AbstractEnvironment() {
	this(new MutablePropertySources());
}

protected AbstractEnvironment(MutablePropertySources propertySources) {
	this.propertySources = propertySources;
	this.propertyResolver = createPropertyResolver(propertySources);
	customizePropertySources(propertySources);
}

customizePropertySources()方法
继续看customizePropertySources()方法

protected void customizePropertySources(MutablePropertySources propertySources) {
	propertySources.addLast(
			new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
	propertySources.addLast(
			new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

这个方法主要用来解析systemProperties和systemEnvironment,我们debug看下解析后的数据

resolveRequiredPlaceholders()方法
到这里,getEnvironment() 差不多结束了,接下来继续看resolveRequiredPlaceholders()方法

private String placeholderPrefix = SystemPropertyUtils.PLACEHOLDER_PREFIX; //"${"
private String placeholderSuffix = SystemPropertyUtils.PLACEHOLDER_SUFFIX; // "}"
private String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR; // ":"


public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
	if (this.strictHelper == null) {
		this.strictHelper = createPlaceholderHelper(false);
	}
	return doResolvePlaceholders(text, this.strictHelper);
}
// 跟进createPlaceholderHelper(false)方法
private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
	return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix,
			this.valueSeparator, ignoreUnresolvablePlaceholders);
}

这一步如果strictHelper属性为空的话,会创建一个PropertyPlaceholderHelper对象并赋值给strictHelper。然后传入占位符的前缀后缀和分隔符。后续的配置文件路径configLocation的解析操作就是交给strictHelper进行的
doResolvePlaceholders()方法

// 到了dodoResolvePlaceholders()方法
return doResolvePlaceholders(text, this.strictHelper);
// 进入方法内部,helper就是传入的strictHelper
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
	return helper.replacePlaceholders(text, this::getPropertyAsRawString);
}
// 继续跟进helper.replacePlaceholders()方法,主要的解析操作就在parseStringValue()方法内部进行
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
	Assert.notNull(value, "'value' must not be null");
	return parseStringValue(value, placeholderResolver, null);
}
protected String parseStringValue(
			String value, PlaceholderResolver placeholderResolver, @Nullable Set visitedPlaceholders) {
		// 获取需要解析的路径是否包含前缀 ‘${‘,如果没有,直接返回
		int startIndex = value.indexOf(this.placeholderPrefix);
		if (startIndex == -1) {
			return value;
		}
		// 封装为StringBuilder,方便进行后续操作
		StringBuilder result = new StringBuilder(value);
		while (startIndex != -1) {
			// 获取后缀 ‘}’ 索引位置
			int endIndex = findPlaceholderEndIndex(result, startIndex);
			// 如果endIndex 为-1 的话,说明不存在后缀‘}’,设置startIndex为-1,跳出while循环
			if (endIndex != -1) {
				// 截取获得需要替换的内容
				String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
				String originalPlaceholder = placeholder;
				// 这里会设置visitedPlaceholders属性,为了避免循环引用
				// 如${aaa},但是解析aaa后,aaa的也是${aaa},这样就会导致无限循环,所以需要
				// 存入visitedPlaceholders防止循环
				if (visitedPlaceholders == null) {
					visitedPlaceholders = new HashSet<>(4);
				}
				if (!visitedPlaceholders.add(originalPlaceholder)) {
					throw new IllegalArgumentException(
							"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
				}
				// Recursive invocation, parsing placeholders contained in the placeholder key.
				placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
				// 开始尝试获取palceholder变量作为key所对应的value
				// 就是遍历前面customizePropertySources()方法获取的属性内容
				String propVal = placeholderResolver.resolvePlaceholder(placeholder);
				// 如果值为空
				if (propVal == null && this.valueSeparator != null) {
					// 获取分隔符 ‘:’的索引
					int separatorIndex = placeholder.indexOf(this.valueSeparator);
					// 如果存在分隔符,则将placeholder分割,然后继续获取内容
					// 如果不存在,直接跳过
					if (separatorIndex != -1) {
						String actualPlaceholder = placeholder.substring(0, separatorIndex);
						String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
						propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
						if (propVal == null) {
							propVal = defaultValue;
						}
					}
				}
				if (propVal != null) {
					// Recursive invocation, parsing placeholders contained in the
					// previously resolved placeholder value.
					// 继续对解析后的值进行递归解析
					// 如: ${aaa} -> aaa -> ${bbb},然后该步骤不要就行对${bbb}继续进行解析
					propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
					result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
					if (logger.isTraceEnabled()) {
						logger.trace("Resolved placeholder '" + placeholder + "'");
					}
					startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
				}
				// 判断是否忽略不能解析的placeholder,true则跳过,继续后面的解析,false直接抛出异常
				else if (this.ignoreUnresolvablePlaceholders) {
					startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
				}
				else {
					throw new IllegalArgumentException("Could not resolve placeholder '" +
							placeholder + "'" + " in value "" + value + """);
				}
				// 将当前placeholder从visitedPlaceholders中移除
				visitedPlaceholders.remove(originalPlaceholder);
			}
			else {
				startIndex = -1;
			}
		}
		//返回解析后的数据
		return result.toString();
	}

解析完成后,将解析后的值复制到this.configLocations属性内

this.configLocations[i] = resolvePath(locations[i]).trim();

到这里,setConfigLocations()方法就分析完了,如果有问题的或者不对的地方,请小伙伴们积极指出,谢谢!!!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/944547.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号