spring之PropertyPlaceholderConfigurer源码解析
spring之PropertyPlaceholderConfigurer源码解析
- PropertyPlaceholderConfigurer介绍
- PropertyPlaceholderConfigurer类结构
- 源码解析
- PropertyResourceConfigurer实现的BeanFactoryPostProcessor接口源码
- PropertyPlaceholderConfigurer实现父类的processProperties方法源码
- PlaceholderConfigurerSupport.doProcessProperties源码
- BeanDefinitionVisitor.visitBeanDefinition源码
- PlaceholderResolvingStringValueResolver.resolveStringValue源码
- PropertyPlaceholderHelper.replacePlaceholders源码
PropertyPlaceholderConfigurer介绍
上一篇博客spring之BeanFactoryPostProcessor源码解析中,通过源码分析了BeanFactoryPostProcessor的作用,这篇将介绍BeanFactoryPostProcessor的一个应用例子PropertyPlaceholderConfigurer。这里先直接介绍它的作用,然后再通过源码解析介绍。相信大部分人都使用过在spring的xml配置文件配置数据源,通常在配置数据源的ip和password等配置时,我们填写的是占位符,而真正的配置会配置在properties文件中。而PropertyPlaceholderConfigurer的作用就包含了上面说的这种场景,修改beanDefiniton真正的属性值为占位符对应的properties文件中配置的值。
PropertyPlaceholderConfigurer类结构
既然是BeanFactoryPostProcessor的一个例子,那说明PropertyPlaceholderConfigurer是有实现BeanFactoryPostProcessor接口。这里我们先分析一下其类结构
可以看到继承关系PropertyPlaceholderConfigurer->PlaceholderConfigurerSupport->PropertyResourceConfigurer。并且PropertyResourceConfigurer实现了BeanFactoryPostProcessor接口。
源码解析
PropertyResourceConfigurer实现的BeanFactoryPostProcessor接口源码
PropertyResourceConfigurer.java
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
//获取所有属性
Properties mergedProps = mergeProperties();
// Convert the merged properties, if necessary.
//转换合并属性
convertProperties(mergedProps);
// Let the subclass process the properties.
//子类实现属性替换过程
processProperties(beanFactory, mergedProps);
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
PropertyPlaceholderConfigurer实现父类的processProperties方法源码
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
throws BeansException {
//将properties属性包装到String解析器PlaceholderResolvingStringValueResolver
//此构造方法在下面的内部类中实现
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
//执行父类PlaceholderConfigurerSupport的doProcessProperties方法
doProcessProperties(beanFactoryToProcess, valueResolver);
}
//内部类
private class PlaceholderResolvingStringValueResolver implements StringValueResolver {
private final PropertyPlaceholderHelper helper;
private final PlaceholderResolver resolver;
public PlaceholderResolvingStringValueResolver(Properties props) {
this.helper = new PropertyPlaceholderHelper(
placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);
this.resolver = new PropertyPlaceholderConfigurerResolver(props);
}
@Override
@Nullable
public String resolveStringValue(String strVal) throws BeansException {
String resolved = this.helper.replacePlaceholders(strVal, this.resolver);
if (trimValues) {
resolved = resolved.trim();
}
return (resolved.equals(nullValue) ? null : resolved);
}
}
PlaceholderConfigurerSupport.doProcessProperties源码
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) {
//构造BeanDefinitionVistor,即BeanDefinition访问器
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
//获取容器中所有的beanName
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))) {
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
try {
//遍历所有的BeanDefinition,并通过前面构造的访问器,将BeanDefinition作为参数执行visitBeanDefinition方法
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);
}
BeanDefinitionVisitor.visitBeanDefinition源码
public void visitBeanDefinition(BeanDefinition beanDefinition) {
visitParentName(beanDefinition);
visitBeanClassName(beanDefinition);
visitFactoryBeanName(beanDefinition);
visitFactoryMethodName(beanDefinition);
visitScope(beanDefinition);
if (beanDefinition.hasPropertyValues()) {
//这里我们关注这个这个方法即可
visitPropertyValues(beanDefinition.getPropertyValues());
}
if (beanDefinition.hasConstructorArgumentValues()) {
ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
visitIndexedArgumentValues(cas.getIndexedArgumentValues());
visitGenericArgumentValues(cas.getGenericArgumentValues());
}
}
//分析visitPropertyValues
protected void visitPropertyValues(MutablePropertyValues pvs) {
PropertyValue[] pvArray = pvs.getPropertyValues();
for (PropertyValue pv : pvArray) {
//这里通过遍历beanDefiniton原有属性值,尝试通过解析器获得一个新的值,如果你到新值则替换掉旧的值
Object newVal = resolveValue(pv.getValue());
if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) {
pvs.add(pv.getName(), newVal);
}
}
}
//分析resolveValue
@Nullable
protected Object resolveValue(@Nullable Object value) {
//按照预想分析,value是一个String类型,因此省略掉一大段类型判断的源码。
else if (value instanceof String) {
//最终调用resolveStringValue
return resolveStringValue((String) value);
}
return value;
}
//分析resolveStringValue
@Nullable
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");
}
//这里最终调用了解析器的resolveStringValue方法
String resolvedValue = this.valueResolver.resolveStringValue(strVal);
// Return original String if not modified.
return (strVal.equals(resolvedValue) ? strVal : resolvedValue);
}
PlaceholderResolvingStringValueResolver.resolveStringValue源码
前面分析了PropertyPlaceholderConfigurer的内部类PlaceholderResolvingStringValueResolver,这个类就定义resolveStringValue方法,继续前面的调用链下来到了resolveStringValue方法
private class PlaceholderResolvingStringValueResolver implements StringValueResolver {
private final PropertyPlaceholderHelper helper;
private final PlaceholderResolver resolver;
public PlaceholderResolvingStringValueResolver(Properties props) {
this.helper = new PropertyPlaceholderHelper(
placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);
this.resolver = new PropertyPlaceholderConfigurerResolver(props);
}
@Override
@Nullable
public String resolveStringValue(String strVal) throws BeansException {
//最终是通过PropertyPlaceholderHelper帮助类进行辅助解析占位符
String resolved = this.helper.replacePlaceholders(strVal, this.resolver);
if (trimValues) {
resolved = resolved.trim();
}
return (resolved.equals(nullValue) ? null : resolved);
}
}
PropertyPlaceholderHelper.replacePlaceholders源码
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
Assert.notNull(value, "'value' must not be null");
//调用parseStringValue
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) {
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 value \"" + value + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return result.toString();
}