spring扩展点之PropertyPlaceholderConfigurer

背景

在使用Spring框架的开发过程中肯定少不了项目的配置文件,通常是Java的Properties文件。并且会通过类PropertyPlaceholderConfigurer在运行时动态替换xml配置文件中的Bean配置项。

先看例子

1
2
3
4
5
6
7
8
<bean id="propertiesConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath*:config.properties</value>
</list>
</property>
</bean>

原理解析

PropertyPlaceholderConfigurer类是如何做到xml配置的bean的配置熟悉的运行时替换的呢?这个离不开Spring框架提供的许多扩展点。这个类依赖的扩展点就是BeanFactoryPostProcessors见下面的类继承图:

BeanFactoryPostProcessors类有一个方法,提供了在Bean创建前对Bean的Definition进行处理的钩子机制。

1
2
//在Bean初始化前被调用(例如在InitializingBean的afterPropertiesSet前)
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

从上面的继承图我们知道PropertyPlaceholderConfigurer继承自类PropertyResourceConfigurer, 而该类实现了接口BeanFactoryPostProcessors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
implements BeanFactoryPostProcessor, PriorityOrdered {
@Override
truepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
truetruetry {
truetruetrueProperties mergedProps = mergeProperties();

truetruetrue// Convert the merged properties, if necessary.
truetruetrueconvertProperties(mergedProps);

truetruetrue// Let the subclass process the properties.
truetruetrueprocessProperties(beanFactory, mergedProps);
truetrue}
truetruecatch (IOException ex) {
truetruetruethrow new BeanInitializationException("Could not load properties", ex);
truetrue}
true}
trueprotected abstract void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
throws BeansException;
}

我们的主角PropertyPlaceholderConfigurer实现了父类中的方法processProperties, 在该类中对xml配置文件中的展位符进行替换处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* Visit each bean definition in the given bean factory and attempt to replace ${...} property
* placeholders with values from the given properties.
*/
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
throws BeansException {

StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
doProcessProperties(beanFactoryToProcess, valueResolver);
}

protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) {

trueBeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);

trueString[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
truefor (String curName : beanNames) {
truetrue// Check that we're not parsing our own bean definition,
truetrue// to avoid failing on unresolvable placeholders in properties file locations.
truetrueif (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
truetruetrueBeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
truetruetruetry {
truetruetruetruevisitor.visitBeanDefinition(bd);
truetruetrue}
truetruetruecatch (Exception ex) {
truetruetruetruethrow new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
truetruetrue}
truetrue}
true}

true// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
truebeanFactoryToProcess.resolveAliases(valueResolver);

true// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
truebeanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}

这样就解开了Spring中xml配置文件中占位符的替换魔法功能。

文章目录
  1. 1. 背景
  2. 2. 先看例子
  3. 3. 原理解析
|