概述
介绍
PropertySourcesPlaceholderConfigurer
是PlaceholderConfigurerSupport
的特殊化实现。它用于解析bean
定义中的属性值,以及注解@Value
的值,使用的属性来源是当前的Spring Environment
对象,以及设置给自己的PropertySources
对象。
在Spring Context 3.1 XSD
或者更高版本中,缺省使用该工具替换了PlaceholderConfigurerSupport
,而<=3.0
较老的Spring Context XSD
中,为了保持和之前的版本兼容,缺省还是使用PropertyPlaceholderConfigurer
。
继承关系
使用
// Spring Boot 自动配置类 PropertyPlaceholderAutoConfiguration
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class PropertyPlaceholderAutoConfiguration {
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
以上例子PropertyPlaceholderAutoConfiguration
定义一个PropertySourcesPlaceholderConfigurer bean
,该bean
作为一个BeanFactoryPostProcessor
,会在容器启动时容器后置处理阶段执行自己的任务。
源代码
源代码版本 Spring Context 5.1.5.RELEASE
package org.springframework.context.support;
import java.io.IOException;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PlaceholderConfigurerSupport;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.ConfigurablePropertyResolver;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources;
import org.springframework.core.env.PropertySourcesPropertyResolver;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringValueResolver;
public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport
implements EnvironmentAware {
/**
* the name given to the PropertySource for the set of
* #mergeProperties() merged properties supplied to this configurer.
*/
public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties";
/**
* the name given to the PropertySource that wraps the
*#setEnvironment environment supplied to this configurer.
*/
public static final String ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME = "environmentProperties";
@Nullable
private MutablePropertySources propertySources;
@Nullable
private PropertySources appliedPropertySources;
@Nullable
private Environment environment;
/**
* Customize the set of PropertySources to be used by this configurer.
* Setting this property indicates that environment property sources and
* local properties should be ignored.
* @see #postProcessBeanFactory
*/
public void setPropertySources(PropertySources propertySources) {
this.propertySources = new MutablePropertySources(propertySources);
}
/**
* PropertySources from the given Environment
* will be searched when replacing ${...} placeholders.
* @see #setPropertySources
* @see #postProcessBeanFactory
*/
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
/**
* Processing occurs by replacing ${...} placeholders in bean definitions by resolving each
* against this configurer's set of PropertySources, which includes:
*
* 1. all org.springframework.core.env.ConfigurableEnvironment#getPropertySources
* environment property sources, if an Environment #setEnvironment is present
*
* 2. #mergeProperties merged local properties, if #setLocation any
* #setLocations have #setProperties been
* #setPropertiesArray specified
*
* 3. any property sources set by calling #setPropertySources
*
* If #setPropertySources is called, environment and local properties will be
* ignored. This method is designed to give the user fine-grained control over property
* sources, and once set, the configurer makes no assumptions about adding additional sources.
*/
// 这是接口 BeanFactoryPostProcessor 约定的方法,会在容器启动过程中的后置处理阶段被调用
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.propertySources == null) {
// 如果外部指定了 this.propertySources, 则直接使用它,否则
// 从当前 Spring 的 Environment 对象和自身的 #mergeProperties 方法调用返回的 Properties 对象构建属性源
// 对象 this.propertySources
this.propertySources = new MutablePropertySources();
if (this.environment != null) {
this.propertySources.addLast(
new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME,
this.environment) {
@Override
@Nullable
public String getProperty(String key) {
return this.source.getProperty(key);
}
}
);
}
try {
PropertySource<?> localPropertySource =
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());
if (this.localOverride) {
this.propertySources.addFirst(localPropertySource);
}
else {
this.propertySources.addLast(localPropertySource);
}
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
// 构造一个基于特定属性源 this.propertySources 对属性值进行解析的属性值解析器
// PropertySourcesPropertyResolver, 对容器中所有的 bean 定义中的属性值,构造函数参数值,
// @Value 注解值进行属性占位符解析和替换
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
this.appliedPropertySources = this.propertySources;
}
/**
* Visit each bean definition in the given bean factory and attempt to replace ${...} property
* placeholders with values from the given properties.
*/
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
final ConfigurablePropertyResolver propertyResolver) throws BeansException {
// 设置属性值解析器所使用的占位符格式参数,缺省为:
// 占位符前缀 ${
// 占位符后缀 }
// 缺省值分隔符 :
propertyResolver.setPlaceholderPrefix(this.placeholderPrefix);
propertyResolver.setPlaceholderSuffix(this.placeholderSuffix);
propertyResolver.setValueSeparator(this.valueSeparator);
// 结合属性 this. ignoreUnresolvablePlaceholders 对 propertyResolver 作进一步封装,
// 封装出来一个 StringValueResolver valueResolver,这是最终要应用的属性值解析器
StringValueResolver valueResolver = strVal -> {
String resolved = (this.ignoreUnresolvablePlaceholders ?
propertyResolver.resolvePlaceholders(strVal) :
propertyResolver.resolveRequiredPlaceholders(strVal));
if (this.trimValues) {
resolved = resolved.trim();
}
return (resolved.equals(this.nullValue) ? null : resolved);
};
// 调用基类 PlaceholderConfigurerSupport 实现的对容器中所有 bean定义进行遍历处理属性值中占位符解析
// 的逻辑
doProcessProperties(beanFactoryToProcess, valueResolver);
}
/**
* 该方法是基类定义的方法,这里的实现直接抛出了异常,因为该实现类实际上使用了另外一个 processProperties
* 方法实现
* Implemented for compatibility with
* org.springframework.beans.factory.config.PlaceholderConfigurerSupport.
* @deprecated in favor of
* #processProperties(ConfigurableListableBeanFactory, ConfigurablePropertyResolver)
* @throws UnsupportedOperationException in this implementation
*/
@Override
@Deprecated
protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) {
throw new UnsupportedOperationException(
"Call processProperties(ConfigurableListableBeanFactory, ConfigurablePropertyResolver) instead");
}
/**
* Return the property sources that were actually applied during
* #postProcessBeanFactory(ConfigurableListableBeanFactory) post-processing.
* @return the property sources that were applied
* @throws IllegalStateException if the property sources have not yet been applied
* @since 4.0
*/
public PropertySources getAppliedPropertySources() throws IllegalStateException {
Assert.state(this.appliedPropertySources != null, "PropertySources have not yet been applied");
return this.appliedPropertySources;
}
}