/*
 * 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 &lt;= 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:

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:
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:
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; } }