Fix placeholder resolution in PropertySourcesPlaceholderConfigurer
Currently, the placeholder resolution algorithm in PropertySourcesPlaceholderConfigurer fails in several scenarios, and the root cause for this category of failures has actually existed since PropertySourcesPlaceholderConfigurer was introduced in Spring Framework 3.1. Specifically, PropertySourcesPlaceholderConfigurer creates its own PropertySourcesPropertyResolver that indirectly delegates to another "nested" PropertySourcesPropertyResolver to interact with PropertySources from the Environment, which results in double placeholder parsing and resolution attempts, and that behavior leads to a whole category of bugs. For example, #27947 was addressed in Spring Framework 5.3.16, and due to #34315 and #34326 we have recently realized that additional bugs exist with placeholder resolution: nested placeholder resolution can fail when escape characters are used, and it is currently impossible to disable the escape character support for nested resolution. To address this category of bugs, we no longer indirectly use or directly create a "nested" PropertySourcesPropertyResolver in PropertySourcesPlaceholderConfigurer. Instead, properties from property sources from the Environment are now accessed directly without duplicate/nested placeholder resolution. See gh-27947 See gh-34326 See gh-34862 Closes gh-34861
This commit is contained in:
@@ -24,12 +24,12 @@ 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.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
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.PropertyResolver;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.PropertySources;
|
||||
import org.springframework.core.env.PropertySourcesPropertyResolver;
|
||||
@@ -133,28 +133,24 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS
|
||||
if (this.propertySources == null) {
|
||||
this.propertySources = new MutablePropertySources();
|
||||
if (this.environment != null) {
|
||||
PropertyResolver propertyResolver = this.environment;
|
||||
// If the ignoreUnresolvablePlaceholders flag is set to true, we have to create a
|
||||
// local PropertyResolver to enforce that setting, since the Environment is most
|
||||
// likely not configured with ignoreUnresolvablePlaceholders set to true.
|
||||
// See https://github.com/spring-projects/spring-framework/issues/27947
|
||||
if (this.ignoreUnresolvablePlaceholders &&
|
||||
(this.environment instanceof ConfigurableEnvironment configurableEnvironment)) {
|
||||
PropertySourcesPropertyResolver resolver =
|
||||
new PropertySourcesPropertyResolver(configurableEnvironment.getPropertySources());
|
||||
resolver.setIgnoreUnresolvableNestedPlaceholders(true);
|
||||
propertyResolver = resolver;
|
||||
PropertySource<?> environmentPropertySource;
|
||||
if (this.environment instanceof ConfigurableEnvironment configurableEnvironment) {
|
||||
environmentPropertySource = new CompositePropertySource(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME,
|
||||
configurableEnvironment.getPropertySources());
|
||||
}
|
||||
PropertyResolver propertyResolverToUse = propertyResolver;
|
||||
this.propertySources.addLast(
|
||||
new PropertySource<>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
|
||||
@Override
|
||||
@Nullable
|
||||
public String getProperty(String key) {
|
||||
return propertyResolverToUse.getProperty(key);
|
||||
}
|
||||
}
|
||||
);
|
||||
else {
|
||||
// Fallback code path that should never apply in a regular scenario, since the
|
||||
// Environment in the ApplicationContext should always be a ConfigurableEnvironment.
|
||||
environmentPropertySource =
|
||||
new PropertySource<>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getProperty(String key) {
|
||||
return super.source.getProperty(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
this.propertySources.addLast(environmentPropertySource);
|
||||
}
|
||||
try {
|
||||
PropertySource<?> localPropertySource =
|
||||
|
||||
Reference in New Issue
Block a user