environment功能
功能说明
在environment存储者spring中所有的变量信息,包括系统变量、jvm变量、以及当前程序定义的变量。同时用户可以通过变量名字获取对应的变量值,同时支持:变量值类型转换、变量占位符的解析等功能。
使用实例
final ConfigurableApplicationContext run = SpringApplication.run(Main.class, args);
//在applicationContext中有environment我们可以通过它获取
final ConfigurableEnvironment environment = run.getEnvironment();
//获取普通的配置变量
final String test = environment.getProperty("test");
//获取同时,并转换为int类型
final Integer number = environment.getProperty("number", Integer.class);
//获取包含占位符的变量
final String placeholderTest = environment.getProperty("placeholderTest${test}");
//获取变量,当不存在时,使用默认值
final String property = environment.getProperty("${default:test}");
environment源码解析
在StandardEnvironment类中继承关系入下图:
其中主要的接口和方法有
- PropertyResolver
- conversion
PropertyResolver 主要实现的是变量的获取以及对于占位符的解析
conversion 主要实现的是对于变量值类型的转换
下面详细结束这些接口与类
父类接口说明
PropertyResolver
这个是顶级接口,主要定义了getProperty等获取变量相关的方法,同时包含 resolvePlaceholders 解析占位符方法。
Environment
在 PropertyResolver 基础上添加了系统运行环境profile相关的接口定义,但当单独解析environmen时无法看出来其作用,故暂不解析。
ConfigurablePropertyResolver
在 PropertyResolver 基础上添加可配置项,属性转换器 convension、占位符的前缀、后缀等配置。
ConfigurableEnvironment
在 Environment 与 ConfigurablePropertyResolver 基础上添加对环境的设置。暂不解析。
父类class说明
AbstractEnvironment
在当前类中,实现了所有的基本方法。除了 环境相关内容。其他都通过 PropertySourcesPropertyResolver来实现。具体解析见下文
StandardEnvironment
在父类的基础上添加系统变量、jvm变量 systemEnvironment sytemProperties。
MutablePropertySources
MutablePropertySources 是PropertySources的子类,在创建PropertySourcesPropertyResolver 对象时需要一个PropertySources对象作为参数。
我们可以看到 MutablePropertySources 就是一个存放批量PropertySource的集合,并且get、add、remove 等相应的方法。
对于 PropertySource 则是存放一个来源的配置。如jvm变量会存放在一个PropertySource 中,而系统变量会全部存在在另一个PropertySource 中,我们平时一个配置文件就是一个PropertySources对象。
至此我们可以看到 在Evironment中。我们所有的配置变量其实都保存在一个y又一个的PropertySource。而所有的 PropertySource又通过list被存放在MutablePropertySources 对象中。
PropertySourcesPropertyResolver
我们可以看到在其构造函数中需要一个PropertySources对象,而在AbstractEnvironment中是new出MutablePropertySources传进来的。根据之前的接口分析。其主要方法有getProperty和resolvePlaceholders两个方法接下来详细解析:
getProperty
//所有的getProperty方法最终都会调用这个方法
//key 变量名称,targetValueType 变量类型,resolveNestedPlaceholders 是否解析占位符
@Nullable
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
//循环遍历MutablePropertySources中的每个propertySource对象,逐一通过get方法获取变量值。
//这也说明MutablePropertySources中排在前面的变量,有着更高的优先度。
for (PropertySource<?> propertySource : this.propertySources) {
if (logger.isTraceEnabled()) {
logger.trace("Searching for key '" + key + "' in PropertySource '" +
propertySource.getName() + "'");
}
Object value = propertySource.getProperty(key);
if (value != null) {
//当resolveNestedPlaceholders 为true时,解析占位符。
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value);
}
logKeyFound(key, propertySource, value);
//如果有必要,转换类型。
return convertValueIfNecessary(value, targetValueType);
}
}
}
if (logger.isTraceEnabled()) {
logger.trace("Could not find key '" + key + "' in any property source");
}
return null;
}
在上面的代码中我们可以看到,其实属性的获取,就是去遍历propertySources中的每个propertySource尝试获取值。而对于占位符和类型转换,分别交给了resolveNestedPlaceholders和convertValueIfNecessary 方法
@Nullable
private PropertyPlaceholderHelper nonStrictHelper;
@Nullable
private PropertyPlaceholderHelper strictHelper;
protected String resolveNestedPlaceholders(String value) {
if (value.isEmpty()) {
return value;
}
return (this.ignoreUnresolvableNestedPlaceholders ?
resolvePlaceholders(value) : resolveRequiredPlaceholders(value));
}
@Override
public String resolvePlaceholders(String text) {
if (this.nonStrictHelper == null) {
this.nonStrictHelper = createPlaceholderHelper(true);
}
return doResolvePlaceholders(text, this.nonStrictHelper);
}
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
if (this.strictHelper == null) {
this.strictHelper = createPlaceholderHelper(false);
}
return doResolvePlaceholders(text, this.strictHelper);
}
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
return helper.replacePlaceholders(text, this::getPropertyAsRawString);
}
对于占位符的解析我们可以看到最终是委托给了PropertyPlaceholderHelper对象。但在PropertyPlaceholderHelper 中没有获取属性的功能。所有需要通过参数传入getPropertyAsRawString方法获取属性。具体方法见下一节。
@Nullable
protected <T> T convertValueIfNecessary(Object value, @Nullable Class<T> targetType) {
if (targetType == null) {
return (T) value;
}
ConversionService conversionServiceToUse = this.conversionService;
if (conversionServiceToUse == null) {
// Avoid initialization of shared DefaultConversionService if
// no standard type conversion is needed in the first place...
if (ClassUtils.isAssignableValue(targetType, value)) {
return (T) value;
}
conversionServiceToUse = DefaultConversionService.getSharedInstance();
}
return conversionServiceToUse.convert(value, targetType);
}
对于属性类型的转换是交给了DefaultConversionService 来做。我们将单独解析这个类。
resolvePlaceholders
@Override
public String resolvePlaceholders(String text) {
if (this.nonStrictHelper == null) {
this.nonStrictHelper = createPlaceholderHelper(true);
}
return doResolvePlaceholders(text, this.nonStrictHelper);
}
PropertyPlaceholderHelper
在上文中。我们看到对于占位符的解析时通过这个类来进行的,我们将解析他的主要方法parseStringValue
//可能包含占位符的字符串,
//placeholderResolver通过key获取属性值,该方法不提供占位符解析
//visitedPlaceholders 递归记录以及便利过的属性
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {
//判断是否包含占位符
int startIndex = value.indexOf(this.placeholderPrefix);
if (startIndex == -1) {
return value;
}
StringBuilder result = new StringBuilder(value);
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 == null) {
visitedPlaceholders = new HashSet<>(4);
}
//判断visitedPlaceholders中是否已经包含当前值,如果有说明以及循环依赖。
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// 递归调用,确保先解析当前字符串中的占位符
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// 已解析后的key获取值
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
//当为空时,以valueSeparator判断是否有默认值
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 value \"" + value + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return result.toString();
}