Spring加载流程源码分析02【setConfigLocations】

  上篇文章介绍了Spring源码中的三步中的super(parent)的代码,本文介绍下setConfigLocations(configLocation)方法


Spring加载流程源码分析03【refresh】
Spring加载流程源码分析01【super】


类图
在这里插入图片描述

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
		throws BeansException {
	// 1.初始化父类
	super(parent);
	// 2.设置本地的配置信息
	setConfigLocations(configLocations);
	// 3.完成Spring容器的初始化
	if (refresh) {
		refresh();
	}
}

setConfigLocations

public void setConfigLocations(String... locations) {
	if (locations != null) {
		Assert.noNullElements(locations, "Config locations must not be null");
		this.configLocations = new String[locations.length];
		for (int i = 0; i < locations.length; i++) {
			//循环取出每一个path参数,在此处就一个“applicationContext.xml“”
			this.configLocations[i] = resolvePath(locations[i]).trim();
		}
	}
	else {
		this.configLocations = null;
	}
}
  1. setConfigLocations主要工作有两个:创建环境对象ConfigurableEnvironment 、处理ClassPathXmlApplicationContext传入的字符串中的占位符;
  2. 环境对象ConfigurableEnvironment中包含了当前JVM的profile配置信息、环境变量、 Java进程变量;
  3. 处理占位符的关键是ConfigurableEnvironment、PropertyResolver、PropertyPlaceholderHelper之间的配合
// 这个方法的目的是替换掉path字符串中的占位符${XXX}这样的内容
protected String resolvePath(String path) {
     // 1.进入getEnvironment()
     // 2.进入resolveRequiredPlaceholders方法
	return getEnvironment().resolveRequiredPlaceholders(path);
}

1.ConfigurableEnvironment

  getEnvironment():创建了ConfigurableEnvironment 对象

public ConfigurableEnvironment getEnvironment() {
	if (this.environment == null) {
		this.environment = createEnvironment();
	}
	return this.environment;
}

在这里插入图片描述提供的方法中可以看出两个功能

  1. 处理profile:Profile是对测试、生产等不同环境下的bean配置,这里我们没有特别设置,所以用到的profile是AbstractEnvironment的defaultProfiles; 之前介绍IOC的时候也介绍过profile。
  2. 处理property
  3. 获取系统环境信息
  4. 合并环境信息

2.PropertyResolver

resolveRequiredPlaceholders(path)
在这里插入图片描述在这里插入图片描述处理占位符的方法

在这里插入图片描述

3.PropertyPlaceholderHelper

@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
	if (this.strictHelper == null) {
		// 创建PropertyPlaceholderHelper对象
		this.strictHelper = createPlaceholderHelper(false);
	}
	return doResolvePlaceholders(text, this.strictHelper);
}

进入doResolvePlaceholders继续查看

private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
	return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() {
		@Override
		public String resolvePlaceholder(String placeholderName) {
			// 
			return getPropertyAsRawString(placeholderName);
		}
	});
}

getPropertyAsRawString的具体实现在PropertySourcesPropertyResolver类中

@Override
protected String getPropertyAsRawString(String key) {
	return getProperty(key, String.class, false);
}

继续跟踪helper.replacePlaceholders(),到了PropertyPlaceholderHelper.parseStringValue方法,这里面逐一找出每个占位符去做替换:

public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
	Assert.notNull(value, "'value' must not be null");
	return parseStringValue(value, placeholderResolver, new HashSet<String>());
}

parseStringValue方法中,找到了占位符后,会调用入参placeholderResolver的resolvePlaceholder(placeholder)方法,也就是上面匿名类的getPropertyAsRawString方法(实际上就是PropertySourcesPropertyResolver.getPropertyAsRawString方法),最终会在PropertySourcesPropertyResolver.getProperty方法中找出所有的属性来匹配占位符

protected String parseStringValue(
			String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {

		StringBuilder result = new StringBuilder(strVal);

		int startIndex = strVal.indexOf(this.placeholderPrefix);
		while (startIndex != -1) {
			int endIndex = findPlaceholderEndIndex(result, startIndex);
			if (endIndex != -1) {
				String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
				String originalPlaceholder = placeholder;
				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);
				// Now obtain the value for the fully resolved key...
				String propVal = placeholderResolver.resolvePlaceholder(placeholder);
				if (propVal == null && this.valueSeparator != null) {
					int separatorIndex = placeholder.indexOf(this.valueSeparator);
					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.
					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());
				}
				else if (this.ignoreUnresolvablePlaceholders) {
					// Proceed with unprocessed value.
					startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
				}
				else {
					throw new IllegalArgumentException("Could not resolve placeholder '" +
							placeholder + "'" + " in string value \"" + strVal + "\"");
				}
				visitedPlaceholders.remove(originalPlaceholder);
			}
			else {
				startIndex = -1;
			}
		}

		return result.toString();
	}
名称作用
ConfigurableEnvironment1.创建PropertyResolver;
2.向PropertyResolver提供环境变量、 Java进程变量
PropertyResolver1.创建PropertyPlaceholderHelper;
2.定义占位符的前缀和后缀(placeholderPrefix、placeholderSuffix);
3.提供getPropertyAsRawString方法给PropertyPlaceholderHelper调用,用来获取指定key对应的环境变量;
PropertyPlaceholderHelper1.找到字符串中的占位符;
2.调用PropertyResolver.getPropertyAsRawString方法,从环境变量中取出占位符对应的值
3.用环境变量的值替换占位符;

至此setConfigLocations的代码就查看到此,后面介绍refresh的代码

  • 5
    点赞
  • 1
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 程序猿惹谁了 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值