概述
介绍
PlaceholderConfigurerSupport
是Spring
提供的一个工具类,用于解析bean
定义中属性值里面的占位符,这是一个抽象类,不能被直接实例化使用。
PlaceholderConfigurerSupport
继承自PropertyResourceConfigurer
,而PropertyResourceConfigurer
具备如下能力 :
- 指定属性源;
Properties
对象形式指定的本地属性源,- 需要从文件路径中加载的外部属性源
- 合并属性源中的属性;
- 对
bean
工厂(可以直接理解为IoC
容器)做某种处理 - 实现了接口
BeanFactoryPostProcessor
,可以在容器后置处理阶段做些事情
PlaceholderConfigurerSupport
在PropertyResourceConfigurer
的基础上对上面第三点提到的"某种处理"做出了明确实现,也就是替换所有bean
定义中属性值和构造函数参数值中的特定格式的属性占位符。
围绕自己的占位符属性替换逻辑,PlaceholderConfigurerSupport
提供了相应的占位符格式设置功能,解析过程中的一些规则的开关功能。具体如下:
-
占位符格式设置功能 :
- 设置占位符前缀,缺省为
${
- 设置占位符后缀,缺省为
}
- 设置占位符缺省值分隔符,缺省为
:
缺省情况下,也就是会处理如下格式的占位符 :
@Value("${person.age}")
<property name="driverClassName" value="${driver}"/>
<property name="url" value="jdbc:${dbname:defaultdb}"/>
- 设置占位符前缀,缺省为
-
解析规则设置功能 :
- 是否修剪值前后的空白,
缺省为 : 不修剪值前后的空白
- 遇到不可解析的占位符时是否抛出异常
缺省为 : 遇到不可解析的占位符时抛出异常
BeanDefinitionStoreException
- 是否修剪值前后的空白,
PlaceholderConfigurerSupport
的方法#doProcessProperties
是其核心逻辑,该方法对容器中除了自己(PlaceholderConfigurerSupport bean
自己)之外的所有bean
定义中的属性值,构造函数参数值进行了属性占位符到相应属性值的解析和替换。
PlaceholderConfigurerSupport
自身并没有实现基类PropertyResourceConfigurer
定义的抽象方法abstract void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
,该方法的真正目的才是基于指定属性源对容器进行某种操作,该方法留给PlaceholderConfigurerSupport
的实现子类使用,具体的可以参考Spring
对PlaceholderConfigurerSupport
的内置实现子类PropertySourcesPlaceholderConfigurer
,PropertySourcesPlaceholderConfigurer
正是实现了该方法,基于指定的属性源,在其中使用PlaceholderConfigurerSupport
提供的方法#doProcessProperties
进行了所定义的处理逻辑。
跟
PlaceholderConfigurerSupport
类似的另外一个属性值解析工具是PropertyOverrideConfigurer
。PlaceholderConfigurerSupport
是分析每个bean
定义内属性值中的占位符将它们替换成相应的属性值,而PropertyOverrideConfigurer
则是解析和处理所有类似beanName.property=value
这种格式的属性设置。
继承关系
源代码
源代码版本 : Spring Beans 5.1.5.RELEASE
package org.springframework.beans.factory.config;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;
public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer
implements BeanNameAware, BeanFactoryAware {
/** Default placeholder prefix: ${ */
public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
/** Default placeholder suffix: } */
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
/** Default value separator: : */
public static final String DEFAULT_VALUE_SEPARATOR = ":";
/** Defaults to #DEFAULT_PLACEHOLDER_PREFIX. */
protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX;
/** Defaults to #DEFAULT_PLACEHOLDER_SUFFIX. */
protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX;
/** Defaults to #DEFAULT_VALUE_SEPARATOR. */
@Nullable
protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;
protected boolean trimValues = false;
@Nullable
protected String nullValue;
protected boolean ignoreUnresolvablePlaceholders = false;
@Nullable
private String beanName;
@Nullable
private BeanFactory beanFactory;
/**
* Set the prefix that a placeholder string starts with.
* The default is #DEFAULT_PLACEHOLDER_PREFIX.
*/
public void setPlaceholderPrefix(String placeholderPrefix) {
this.placeholderPrefix = placeholderPrefix;
}
/**
* Set the suffix that a placeholder string ends with.
* The default is #DEFAULT_PLACEHOLDER_SUFFIX.
*/
public void setPlaceholderSuffix(String placeholderSuffix) {
this.placeholderSuffix = placeholderSuffix;
}
/**
* Specify the separating character between the placeholder variable
* and the associated default value, or null if no such
* special character should be processed as a value separator.
* The default is #DEFAULT_VALUE_SEPARATOR.
*/
public void setValueSeparator(@Nullable String valueSeparator) {
this.valueSeparator = valueSeparator;
}
/**
* Specify whether to trim resolved values before applying them,
* removing superfluous whitespace from the beginning and end.
* Default is false.
* @since 4.3
*/
public void setTrimValues(boolean trimValues) {
this.trimValues = trimValues;
}
/**
* Set a value that should be treated as null when resolved
* as a placeholder value: e.g. "" (empty String) or "null".
* Note that this will only apply to full property values,
* not to parts of concatenated values.
*
* By default, no such null value is defined. This means that
* there is no way to express null as a property value
* unless you explicitly map a corresponding value here.
*/
public void setNullValue(String nullValue) {
this.nullValue = nullValue;
}
/**
* Set whether to ignore unresolvable placeholders.
* Default is "false": An exception will be thrown if a placeholder fails
* to resolve. Switch this flag to "true" in order to preserve the placeholder
* String as-is in such a case, leaving it up to other placeholder configurers
* to resolve it.
*/
public void setIgnoreUnresolvablePlaceholders(boolean ignoreUnresolvablePlaceholders) {
this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
}
/**
* Only necessary to check that we're not parsing our own bean definition,
* to avoid failing on unresolvable placeholders in properties file locations.
* The latter case can happen with placeholders for system properties in
* resource locations.
* @see #setLocations
* @see org.springframework.core.io.ResourceEditor
*/
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
/**
* Only necessary to check that we're not parsing our own bean definition,
* to avoid failing on unresolvable placeholders in properties file locations.
* The latter case can happen with placeholders for system properties in
* resource locations.
* @see #setLocations
* @see org.springframework.core.io.ResourceEditor
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
// 该方法是 PlaceholderConfigurerSupport 对容器中所有 bean 定义进行处理的核心逻辑方法,
// 该方法留给具体实现子类使用,当然具体实现子类也可以重写该方法或者不使用该方法。
//
// Spring 提供的 PlaceholderConfigurerSupport 具体实现子类 PropertyPlaceholderConfigurer
// 直接使用了该方法。
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) {
// BeanDefinitionVisitor 是一个专门为 PropertyPlaceholderConfigurer 设计的 bean 定义
// 访问器,主要是遍历 bean 定义中的属性值和构造函数参数值字符串,使用 valueResolver
// 解析相应值字符串中的占位符,结合给定的属性源,将占位符其替换为相应的属性值
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
// 获取容器中所有的 bean 名称,这样可以访问到容器中所有的 bean 定义
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.
// this.beanName 记录了当前对象,也就是当前 PlaceholderConfigurerSupport 对象的
// bean 名称,这里的 for 循环会使用 visitor 处理处理当前 PlaceholderConfigurerSupport 对象
// 之外的所有 bean 定义
if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
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.
// bean 的别名,以及别名的目标bean名称中也可能使用占位符,这里也做处理
beanFactoryToProcess.resolveAliases(valueResolver);
// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
// 将这里所使用的值解析器 valueResolver 添加到容器,用于处理类似注解属性中的嵌入值。
beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}
}