spring-core env包PropertyResolver接口
一、接口继承图
二、接口类功能概述与实现
PropertyResolver接口定义了按属性名获取对应属性配置的接口以及解析字符串中的属性表达式的接口,如${foo}/abc,foo对应的属性值为123,解析后为123/abc。
Environment接口继承自PropertyResolver,增加了获取Profiles相关接口
ConfigurablePropertyResolver接口继承自PropertyResolver,增加实现PropertyResolver所需的辅助接口
AbstractPropertyResolver是ConfigurablePropertyResolver接口的抽象实现类,提供了大部分接口方法的默认实现,将核心的getProperty(String key, Class<T> targetType)方法留给子类实现,resolvePlaceholders(String text)方法则由PropertyPlaceholderHelper提供默认实现。PropertySourcesPropertyResolver是该类的默认实现类,从全局变量PropertySources对象获取属性名key对应的属性值,查找时会遍历PropertySources中包含的多个PropertySource,直到找到对应的属性值。
ConfigurableEnvironment继承自Environment和ConfigurablePropertyResolver两个接口,并增加了Profiles维护,获取系统属性,系统环境变量的实用接口。
AbstractEnvironment为ConfigurableEnvironment接口的抽象实现类,提供了该接口的所有方法的默认实现,其中ConfigurablePropertyResolver的接口PropertySourcesPropertyResolver实例实现,将核心的MutablePropertySources全局变量包含的多个PropertySources的初始化交给子类实现,即protected方法customizePropertySources(MutablePropertySources propertySources)。
StandardEnvironment是AbstractEnvironment的默认实现子类,覆写了customizePropertySources方法,如下:
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
即spring 容器查找环境属性配置时会优先从System Properties中查找,然后是System Env。
重点关注PropertyPlaceholderHelper类的实现,代码解读如下:
public class PropertyPlaceholderHelper {
private static final Log logger = LogFactory.getLog(PropertyPlaceholderHelper.class);
private static final Map<String, String> wellKnownSimplePrefixes = new HashMap<>(4);
static {
wellKnownSimplePrefixes.put("}", "{");
wellKnownSimplePrefixes.put("]", "[");
wellKnownSimplePrefixes.put(")", "(");
}
private final String placeholderPrefix;
private final String placeholderSuffix;
private final String simplePrefix;
@Nullable
private final String valueSeparator;
private final boolean ignoreUnresolvablePlaceholders;
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) {
this(placeholderPrefix, placeholderSuffix, null, true);
}
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix,
@Nullable String valueSeparator, boolean ignoreUnresolvablePlaceholders) {
Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");
Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");
this.placeholderPrefix = placeholderPrefix;
this.placeholderSuffix = placeholderSuffix;
String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix);
if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) {
this.simplePrefix = simplePrefixForSuffix;
}
else {
this.simplePrefix = this.placeholderPrefix;
}
this.valueSeparator = valueSeparator;
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
}
public String replacePlaceholders(String value, final Properties properties) {
Assert.notNull(properties, "'properties' must not be null");
return replacePlaceholders(value, properties::getProperty);
}
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
Assert.notNull(value, "'value' must not be null");
return parseStringValue(value, placeholderResolver, new HashSet<>());
}
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
StringBuilder result = new StringBuilder(value);
//找到表达式前缀在字符串中第一次出现的位置
int startIndex = value.indexOf(this.placeholderPrefix);
//目标字符串中所有的字符
while (startIndex != -1) {
//找到表达式后缀在字符串中与前缀对应的最后一次的位置,需要考虑嵌套的情形
//如ab${cd${ef}}
int endIndex = findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
//取出中间的字符串
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
//visitedPlaceholders用于避免递归导致的死循环
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// 递归处理嵌套的属性表达式
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// 找到对应的属性值
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) {
//如果属性值不为空再做递归调用,解析属性值中包含的属性表达式
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
//将属性表达式替换成最终的属性值
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (logger.isTraceEnabled()) {
logger.trace("Resolved placeholder '" + placeholder + "'");
}
System.out.println("result-->"+result+",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();
}
private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
//计算表达式前缀后第一个字符的位置
int index = startIndex + this.placeholderPrefix.length();
//记录嵌套的层数
int withinNestedPlaceholder = 0;
//遍历表达式前缀后的每一个字符
while (index < buf.length()) {
//逐个字符比较判断是否是表达式后缀
if (StringUtils.substringMatch(buf, index, this.placeholderSuffix)) {
if (withinNestedPlaceholder > 0) {
//找到嵌套表达式的后缀,将嵌套的层数减1
withinNestedPlaceholder--;
index = index + this.placeholderSuffix.length();
}
else {
//匹配到了后缀且是与前缀对应的一个后缀
return index;
}
}
//逐个字符比较判断是否是表达式前缀
else if (StringUtils.substringMatch(buf, index, this.simplePrefix)) {
//如果是前缀表明是嵌套
withinNestedPlaceholder++;
index = index + this.simplePrefix.length();
}
else {
index++;
}
}
return -1;
}
@FunctionalInterface
public interface PlaceholderResolver {
@Nullable
String resolvePlaceholder(String placeholderName);
}
}
参考测试用例:
@Test
public void testRecurseInPlaceholder() {
PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}");
String text = "foo=${b${inner}}";
Properties props = new Properties();
props.setProperty("bar", "bar");
props.setProperty("inner", "ar");
assertEquals("foo=bar",helper.replacePlaceholders(text, props));
text = "${top}";
props = new Properties();
props.setProperty("top", "${child}+${child}");
props.setProperty("child", "${${differentiator}.grandchild}");
props.setProperty("differentiator", "first");
props.setProperty("first.grandchild", "actualValue");
assertEquals("actualValue+actualValue", helper.replacePlaceholders(text, props));
}
测试用例运行结果:
result-->bar,placeholder-->inner
result-->foo=bar,placeholder-->bar
result-->first.grandchild,placeholder-->differentiator
result-->actualValue,placeholder-->first.grandchild
result-->actualValue+${child},placeholder-->child
result-->first.grandchild,placeholder-->differentiator
result-->actualValue,placeholder-->first.grandchild
result-->actualValue+actualValue,placeholder-->child
result-->actualValue+actualValue,placeholder-->top