前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring加载流程源码分析02【setConfigLocations】

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

作者头像
用户4919348
发布2019-04-02 11:27:22
9950
发布2019-04-02 11:27:22
举报
文章被收录于专栏:波波烤鸭波波烤鸭

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

类图

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
		throws BeansException {
	// 1.初始化父类
	super(parent);
	// 2.设置本地的配置信息
	setConfigLocations(configLocations);
	// 3.完成Spring容器的初始化
	if (refresh) {
		refresh();
	}
}

setConfigLocations

代码语言:javascript
复制
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之间的配合
代码语言:javascript
复制
// 这个方法的目的是替换掉path字符串中的占位符${XXX}这样的内容
protected String resolvePath(String path) {
     // 1.进入getEnvironment()
     // 2.进入resolveRequiredPlaceholders方法
	return getEnvironment().resolveRequiredPlaceholders(path);
}

1.ConfigurableEnvironment

  getEnvironment():创建了ConfigurableEnvironment 对象

代码语言:javascript
复制
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

代码语言:javascript
复制
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
	if (this.strictHelper == null) {
		// 创建PropertyPlaceholderHelper对象
		this.strictHelper = createPlaceholderHelper(false);
	}
	return doResolvePlaceholders(text, this.strictHelper);
}

进入doResolvePlaceholders继续查看

代码语言:javascript
复制
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类中

代码语言:javascript
复制
@Override
protected String getPropertyAsRawString(String key) {
	return getProperty(key, String.class, false);
}

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

代码语言:javascript
复制
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方法中找出所有的属性来匹配占位符

代码语言:javascript
复制
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();
	}

名称

作用

ConfigurableEnvironment

1.创建PropertyResolver;2.向PropertyResolver提供环境变量、 Java进程变量

PropertyResolver

1.创建PropertyPlaceholderHelper;2.定义占位符的前缀和后缀(placeholderPrefix、placeholderSuffix);3.提供getPropertyAsRawString方法给PropertyPlaceholderHelper调用,用来获取指定key对应的环境变量;

PropertyPlaceholderHelper

1.找到字符串中的占位符;2.调用PropertyResolver.getPropertyAsRawString方法,从环境变量中取出占位符对应的值3.用环境变量的值替换占位符;

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年02月22日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • setConfigLocations
    • 1.ConfigurableEnvironment
      • 2.PropertyResolver
        • 3.PropertyPlaceholderHelper
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档