/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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;
Specialization of PlaceholderConfigurerSupport
that resolves ${...} placeholders within bean definition property values and @Value
annotations against the current Spring Environment
and its set of PropertySources
. This class is designed as a general replacement for PropertyPlaceholderConfigurer
. It is used by default to support the property-placeholder
element in working against the spring-context-3.1 or higher XSD; whereas, spring-context versions <= 3.0 default to PropertyPlaceholderConfigurer
to ensure backward compatibility. See the spring-context XSD documentation for complete details.
Any local properties (e.g. those added via PropertiesLoaderSupport.setProperties
, PropertiesLoaderSupport.setLocations
et al.) are added as a PropertySource
. Search precedence of local properties is based on the value of the localOverride
property, which is by default false
meaning that local properties are to be searched last, after all environment property sources.
See ConfigurableEnvironment
and related javadocs for details on manipulating environment property sources.
Author: Chris Beams, Juergen Hoeller See Also: Since: 3.1
/**
* Specialization of {@link PlaceholderConfigurerSupport} that resolves ${...} placeholders
* within bean definition property values and {@code @Value} annotations against the current
* Spring {@link Environment} and its set of {@link PropertySources}.
*
* <p>This class is designed as a general replacement for {@code PropertyPlaceholderConfigurer}.
* It is used by default to support the {@code property-placeholder} element in working against
* the spring-context-3.1 or higher XSD; whereas, spring-context versions <= 3.0 default to
* {@code PropertyPlaceholderConfigurer} to ensure backward compatibility. See the spring-context
* XSD documentation for complete details.
*
* <p>Any local properties (e.g. those added via {@link #setProperties}, {@link #setLocations}
* et al.) are added as a {@code PropertySource}. Search precedence of local properties is
* based on the value of the {@link #setLocalOverride localOverride} property, which is by
* default {@code false} meaning that local properties are to be searched last, after all
* environment property sources.
*
* <p>See {@link org.springframework.core.env.ConfigurableEnvironment} and related javadocs
* for details on manipulating environment property sources.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see org.springframework.core.env.ConfigurableEnvironment
* @see org.springframework.beans.factory.config.PlaceholderConfigurerSupport
* @see org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
*/
public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware {
"localProperties" is the name given to the PropertySource
for the set of merged properties supplied to this configurer. /**
* {@value} is the name given to the {@link PropertySource} for the set of
* {@linkplain #mergeProperties() merged properties} supplied to this configurer.
*/
public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties";
"environmentProperties" is the name given to the PropertySource
that wraps the environment supplied to this configurer. /**
* {@value} is the name given to the {@link PropertySource} that wraps the
* {@linkplain #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 Also:
/**
* Customize the set of {@link PropertySources} to be used by this configurer.
* <p>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 Also:
/**
* {@code PropertySources} from the given {@link 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:
- all
environment property sources, if an
Environment
is present - merged local properties, if any have been specified
- 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.
/**
* Processing occurs by replacing ${...} placeholders in bean definitions by resolving each
* against this configurer's set of {@link PropertySources}, which includes:
* <ul>
* <li>all {@linkplain org.springframework.core.env.ConfigurableEnvironment#getPropertySources
* environment property sources}, if an {@code Environment} {@linkplain #setEnvironment is present}
* <li>{@linkplain #mergeProperties merged local properties}, if {@linkplain #setLocation any}
* {@linkplain #setLocations have} {@linkplain #setProperties been}
* {@linkplain #setPropertiesArray specified}
* <li>any property sources set by calling {@link #setPropertySources}
* </ul>
* <p>If {@link #setPropertySources} is called, <strong>environment and local properties will be
* ignored</strong>. 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.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.propertySources == null) {
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);
}
}
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.
/**
* 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);
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);
};
doProcessProperties(beanFactoryToProcess, valueResolver);
}
Implemented for compatibility with PlaceholderConfigurerSupport
. Throws: - UnsupportedOperationException – in this implementation
Deprecated: in favor of processProperties(ConfigurableListableBeanFactory, ConfigurablePropertyResolver)
/**
* Implemented for compatibility with
* {@link org.springframework.beans.factory.config.PlaceholderConfigurerSupport}.
* @deprecated in favor of
* {@link #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 post-processing
. Throws: - IllegalStateException – if the property sources have not yet been applied
Returns: the property sources that were applied Since: 4.0
/**
* Return the property sources that were actually applied during
* {@link #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;
}
}