spring-boot
spring-boot copied to clipboard
Propose new spring.autoconfigure.exclusion property binding as Map to support multiple property sources
Currently the spring.autoconfigure.exclude
property is bound as a List<Class<?>>
. This is a problem as collections cannot be merged across different property sources or individual elements removed. Additionally it requires property sources with higher precedence to have global knowledge of all preexisting exclusion from other sources in order to append a new exclusion.
This is a frequent pain-point for us and others. See #27414 - Consider merging spring.autoconfigure.exclude from multiple profiles and https://github.com/spring-projects/spring-boot/issues/9137
Understandably merging / overriding logic for collections is difficult - refer to https://github.com/spring-projects/spring-boot/issues/12444#issuecomment-372410949
I propose a new configuration property (E.g. spring.autoconfigure.exclusions
or perhaps some other property if too similarly named) that is bound as a Map<Class<?>, Boolean>
. Binding to a map will allow merging from different property sources and profiles. E.g.
---
spring:
config.activate.on-profile: nosecurity
autoconfigure:
exclusions:
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration: true
org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration: true
---
spring:
config.activate.on-profile: noredis
autoconfigure:
exclusions:
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration: true
Including the class name in the key is not too different from the logging.level.<class>
properties and similar to management.health.<name>.enabled
.
I have a custom EnvironmentPostProcessor that I think achieves my goal by rebinding the spring.autoconfigure.exclude
property from my custom spring.autoconfigure.exclusions
property? But it would be nice if spring-boot had first class support for this. For posterity here it is
@Order(Ordered.LOWEST_PRECEDENCE)
public class AutoConfigureExcludeEnvironmentPostProcessor implements EnvironmentPostProcessor {
private static final String SPRING_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
private static final String SPRING_AUTOCONFIGURE_EXCLUDEMAP = "spring.autoconfigure.exclusion";
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Binder binder = Binder.get(environment);
Set<String> disabled = new HashSet<>();
binder.bind(SPRING_AUTOCONFIGURE_EXCLUDE, Bindable.listOf(String.class)).ifBound(disabled::addAll);
Map<String, Boolean> excludeMap =
binder.bind(SPRING_AUTOCONFIGURE_EXCLUDEMAP, Bindable.mapOf(String.class, Boolean.class))
.orElseGet(Collections::emptyMap);
for (Map.Entry<String, Boolean> entry : excludeMap.entrySet()) {
if (entry.getValue()) {
disabled.add(entry.getKey());
} else {
// override if class is present in 'spring.autoconfigure.exclude' property
disabled.remove(entry.getKey());
}
}
if (!disabled.isEmpty() || environment.containsProperty(SPRING_AUTOCONFIGURE_EXCLUDE)) {
environment.getPropertySources().addFirst(new MapPropertySource(
AutoConfigureExcludeEnvironmentPostProcessor.class.getSimpleName(),
Map.of(SPRING_AUTOCONFIGURE_EXCLUDE, disabled)
));
}
}
}