Spring 工具类 PlaceholderConfigurerSupport (抽象基类)
概述
Spring
PlaceholderConfigurerSupport
是一个抽象基类,抽象了bean
定义属性值中的占位符解析的功能。它继承自PropertyResourceConfigurer
。基类已经定义了要在bean
容器后置处理阶段对容器中所有bean
定义属性进行处理,而PlaceholderConfigurerSupport
则进一步约定了要进行的属性值处理是:解析属性值中的占位符,同时提供了进行处理所需的一些属性(占位符前后缀等),以及一些工具方法。实现子类会从一个属性文件或者其他org.springframework.core.env.PropertySource
属性源"拉取(pull)"属性值,然后使用PlaceholderConfigurerSupport
约定的属性和属性值占位符替换方法处理bean
定义。
缺省的占位符格式为${...}
,遵从Ant/Log4J/JSP EL
风格。PlaceholderConfigurerSupport
允许设置不同的占位符前缀后缀。
如果是XML
方式定义bean
,占位符例子如下 :
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="jdbc:${dbname}"/>
</bean>
对应的属性文件内容如下 :
driver=com.mysql.jdbc.Driver
dbname=mysql:mydb
而如果是注解方式使用占位符,占位符例子如下 :
@Value("${person.age}")
另外支持嵌套使用占位符:
rootPath=myrootdir
subPath=${rootPath}/subdir
如果占位符无法被解析,可以抛出一个异常BeanDefinitionStoreException
,也可以置之不理,这个机制通过属性ignoreUnresolvablePlaceholders
来控制,ignoreUnresolvablePlaceholders
为false
表示无法解析占位符时抛出异常。这也是缺省值。
PlaceholderConfigurerSupport
所在包 :org.springframework.beans.factory.config
。
PlaceholderConfigurerSupport
在类层级关系中的位置如下图所示:
源代码解析
基类
所实现接口
1.BeanNameAware
2.BeanFactoryAware
属性定义
/** Default placeholder prefix: {@value}. */
// 缺省使用的占位符前缀
public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
/** Default placeholder suffix: {@value}. */
// 缺省使用的占位符后缀
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
/** Default value separator: {@value}. */
// 缺省使用的值分隔符
public static final String DEFAULT_VALUE_SEPARATOR = ":";
/** Defaults to {@value #DEFAULT_PLACEHOLDER_PREFIX}. */
// 实例成员所用的占位符前缀
protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX;
/** Defaults to {@value #DEFAULT_PLACEHOLDER_SUFFIX}. */
// 实例成员所用的占位符后缀
protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX;
/** Defaults to {@value #DEFAULT_VALUE_SEPARATOR}. */
// 实例成员所用的值分隔符
@Nullable
protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;
// 是否要对值做 trim
protected boolean trimValues = false;
// 遇到占位符对应属性值为""或者null时的替代填充值
@Nullable
protected String nullValue;
// 不能解析的占位符是否抛出异常, false 表示抛出异常, true 表示不抛出异常
protected boolean ignoreUnresolvablePlaceholders = false;
// 对应 BeanNameAware 接口方法setBeanName()
// 用于记录当前bean的名称
@Nullable
private String beanName;
// 对应 BeanFactoryAware 接口方法setBeanFactory()
// 用于记录当前bean所在容器,也就是需要处理的bean定义所在的容器
@Nullable
private BeanFactory beanFactory;
对于上述实例成员属性,PlaceholderConfigurerSupport
都提供了相应的set
方法,所以上面带缺省值的属性都可以被覆盖。
主要功能方法
除了对上述实例成员的set
方法之外,PlaceholderConfigurerSupport
仅仅提供了一个功能方法doProcessProperties
,使用指定的字符串值解析器处理容器中所有的bean
定义的属性。
doProcessProperties()
// 参数 beanFactoryToProcess : 要处理的bean定义所属的容器
// 参数 valueResolver : 属性值解析器
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) {
// 使用指定的字符串值解析器 valueResolver 定义一个bean定义访问器,
// 该访问器的目的就是每次访问一个bean定义,将其中所有可能包含占位符的属性值,包括bean属性值,
// bean构造函数参数值,双亲bean名称,bean类名,bean工厂bean名称,bean工厂方法名称,作用域
// 等都遍历一遍,进行需要的占位符解析
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
// 获取容器中所有bean的名称
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
// 逐个bean定义进行属性值占位符解析
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定义不是自己的bean定义
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
try {
// 对bean定义bd进行属性值占位符解析
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);
}
总结
从上面分析可以看出:
-
PlaceholderConfigurerSupport
继承自PropertyResourceConfigurer
,所以它具备PropertyResourceConfigurer
定义的所有能力。 -
PlaceholderConfigurerSupport
实现了接口BeanNameAware
,所以它的bean
实例知道自己的bean
名称。 -
PlaceholderConfigurerSupport
实现了接口BeanFactoryAware
,所以它知道自己的容器是谁。 -
PlaceholderConfigurerSupport
提供了实现子类需要的一些属性的设置和缺省值,比如占位符前后缀,值分隔符等。 -
PlaceholderConfigurerSupport
实现了一个工具方法doProcessProperties()
,该方法处理容器中除了自身bean
定义之外的所有其他bean
定义,对它们的属性值中的占位符进行解析。 - 不过,
PlaceholderConfigurerSupport
仍未对基类PropertyResourceConfigurer
定义的抽象方法processProperties
提供实现。换句话讲,如果想使用PlaceholderConfigurerSupport
的能力的话,需要继续提供实现子类。