工具类的使用
return StrFillTool.item("test1", test1).item("test2", test2).target("/{test1}/{test2}");
public final class StrFillTool {
private static final String PLACE_HOLDER_PREFIX = "{";
private static final String PLACE_HOLDER_SUFFIX = "}";
private static final String VALUE_SEPARATOR = ":";
private static final String SIMPLE_PREFIX = "{";
public static Builder item(String name, Object value) {
return new Builder(name, value);
}
public static final class Builder {
private Map<String, Object> dataMap;
public Builder(String name, Object value) {
this.dataMap = new HashMap<>();
this.dataMap.put(name, value);
}
public Builder item(String name, Object value) {
this.dataMap.put(name, value);
return this;
}
public String target(String targetStr) {
return target(targetStr, false);
}
public String target(String targetStr, boolean ignoreNull) {
return parseStringValue(targetStr, new PlaceholderResolver() {
@Override
public String resolvePlaceholder(String placeholderName) {
Object placeholderValue = dataMap.get(placeholderName);
return null == placeholderValue ? null : placeholderValue.toString();
}
}, new HashSet<String>(), ignoreNull);
}
private static String parseStringValue(String strVal, PlaceholderResolver placeholderResolver
, Set<String> visitedPlaceholders, Boolean ignoreUnresolvablePlaceholders) {
StringBuilder result = new StringBuilder(strVal);
int startIndex = strVal.indexOf(PLACE_HOLDER_PREFIX);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
String placeholder = result.substring(startIndex + PLACE_HOLDER_PREFIX.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, ignoreUnresolvablePlaceholders);
// Now obtain the value for the fully resolved key...
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
if (propVal == null && VALUE_SEPARATOR != null) {
int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + VALUE_SEPARATOR.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, ignoreUnresolvablePlaceholders);
result.replace(startIndex, endIndex + PLACE_HOLDER_SUFFIX.length(), propVal);
startIndex = result.indexOf(PLACE_HOLDER_PREFIX, startIndex + propVal.length());
}
else if (ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = result.indexOf(PLACE_HOLDER_PREFIX, endIndex + PLACE_HOLDER_SUFFIX.length());
}
else {
throw new IllegalArgumentException("Could not resolve placeholder '" +
placeholder + "'" + " in string value \"" + strVal + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return result.toString();
}
private static int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
int index = startIndex + PLACE_HOLDER_PREFIX.length();
int withinNestedPlaceholder = 0;
while (index < buf.length()) {
if (StringUtils.substringMatch(buf, index, PLACE_HOLDER_SUFFIX)) {
if (withinNestedPlaceholder > 0) {
withinNestedPlaceholder--;
index = index + PLACE_HOLDER_SUFFIX.length();
}
else {
return index;
}
}
else if (StringUtils.substringMatch(buf, index, SIMPLE_PREFIX)) {
withinNestedPlaceholder++;
index = index + SIMPLE_PREFIX.length();
}
else {
index++;
}
}
return -1;
}
}
private interface PlaceholderResolver {
String resolvePlaceholder(String placeholderName);
}
private StrFillTool() {}
}
PropertyResourceConfigurer.postProcessBeanFactory方法
/**
* {@linkplain #mergeProperties Merge}, {@linkplain #convertProperties convert} and
* {@linkplain #processProperties process} properties against the given bean factory.
* @throws BeanInitializationException if any properties cannot be loaded
*/
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
//加载locations属性中配置的所有properties文件中的属性
Properties mergedProps = mergeProperties();
//prop做key,value转换
convertProperties(mergedProps);
//解析el表达式中的属性,获取值,并加载到bean属性中
processProperties(beanFactory, mergedProps);
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
StringValueResolver接口是一个通配符解析接口,默认解析替换${}中的值。
我们再进到doProcessProperties方法中看一下。
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) {
//注册StringValueResolver解析器
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
//从BeanFactory中获取注册的beanNames
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
for (String curName : beanNames) {
// Check that we're not parsing our own bean definition,
// to avoid failing on unresolvable placeholders in properties file locations.
if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
//初始化bean实例(自己除外)
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
try {
//设置元数据
visitor.visitBeanDefinition(bd);
}
catch (Exception ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
}
}
}
// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
beanFactoryToProcess.resolveAliases(valueResolver);
// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}
这段代码很好理解
1.注册StringValueResolver解析器
2.从BeanFactory中获取注册的beanNames
3.初始化bean实例(自己除外)
4.调用visitor.visitBeanDefinition(bd);方法设置元数据。
我们再继续跟到visitBeanDefinition(bd)中去。
/**
* Traverse the given BeanDefinition object and the MutablePropertyValues
* and ConstructorArgumentValues contained in them.
* @param beanDefinition the BeanDefinition object to traverse
* @see #resolveStringValue(String)
*/
public void visitBeanDefinition(BeanDefinition beanDefinition) {
visitParentName(beanDefinition);
visitBeanClassName(beanDefinition);
visitFactoryBeanName(beanDefinition);
visitFactoryMethodName(beanDefinition);
visitScope(beanDefinition);
visitPropertyValues(beanDefinition.getPropertyValues());
ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
visitIndexedArgumentValues(cas.getIndexedArgumentValues());
visitGenericArgumentValues(cas.getGenericArgumentValues());
}
我们继续跟到visitPropertyValues(beanDefinition.getPropertyValues())方法里
/**
* Resolve the given String value, for example parsing placeholders.
* @param strVal the original String value
* @return the resolved String value
*/
protected String resolveStringValue(String strVal) {
if (this.valueResolver == null) {
throw new IllegalStateException("No StringValueResolver specified - pass a resolver " +
"object into the constructor or override the 'resolveStringValue' method");
}
String resolvedValue = this.valueResolver.resolveStringValue(strVal);
// Return original String if not modified.
return (strVal.equals(resolvedValue) ? strVal : resolvedValue);
}
跟到StringValueResolver.resolveStringValue(String strVal)方法中
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...
// 返回配置文件中对应属性的value值
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();
}
大致逻辑,递归调用解析出${}中的字符串
通过String propVal = placeholderResolver.resolvePlaceholder(placeholder);方法从prop对象中获取到配置文件中对应的value。
返回配置文件中的value值到BeanDefinition对象中的MutablePropertyValues对象中
protected void visitPropertyValues(MutablePropertyValues pvs) {
PropertyValue[] pvArray = pvs.getPropertyValues();
for (PropertyValue pv : pvArray) {
Object newVal = resolveValue(pv.getValue());
if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) {
pvs.add(pv.getName(), newVal);
}
}
}