Hi,
We have applications that have followed Spring Framework upgrades since version 3 up to version 5. There configurations were converted from XML to annotations.
When Spring Boot came out, we didn't want to integrate it because of the opt-out auto-configuration: * this works probably well on greenfield projects (at least at the beginning), but is tedious on legacy ones * what if someone mistakenly add a direct or transitive dependency containing an unexpected Spring Boot AutoConfiguration?
So we thought we were going to keep going with Spring without Spring Boot. Then, 2 years ago we needed some Spring Cloud features. We discovered that it was almost impossible to setup Spring Cloud without pulling its AutoConfiguration with Spring Boot.
Take a look at one of its spring.factories
:
# AutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.client.CommonsClientAutoConfiguration,\
org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration,\
org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.hypermedia.CloudHypermediaAutoConfiguration,\
org.springframework.cloud.client.loadbalancer.AsyncLoadBalancerAutoConfiguration,\
org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration,\
org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration,\
org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration,\
org.springframework.cloud.commons.httpclient.HttpClientConfiguration,\
org.springframework.cloud.commons.util.UtilAutoConfiguration,\
org.springframework.cloud.configuration.CompatibilityVerifierAutoConfiguration,\
org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration,\
org.springframework.cloud.commons.security.ResourceServerTokenRelayAutoConfiguration
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.client.HostInfoEnvironmentPostProcessor
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.cloud.configuration.CompatibilityNotMetFailureAnalyzer
We came to the conclusion that Spring Boot was now de-facto mandatory.
We included Spring Boot in our projects but by making sure to opt-out from all AutoConfiguration by default using an org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
implementation:
class MyAutoConfigurationImportFilter
implements AutoConfigurationImportFilter, BeanClassLoaderAware {
private List<String> factoryNames;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
factoryNames =
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader);
}
@Override
public boolean[] match(
String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
boolean[] result = new boolean[autoConfigurationClasses.length];
for (int i = 0; i < autoConfigurationClasses.length; i++) {
String autoConfigurationClass = autoConfigurationClasses[i];
result[i] =
autoConfigurationClass == null
|| !factoryNames.contains(autoConfigurationClass)
|| AutoConfigurationAllowList.INSTANCE.isAllowed(autoConfigurationClass);
}
return result;
}
}
This filter excludes all AutoConfiguration that are not part of com.mycompany
or org.springframework.cloud
.
For the Spring Cloud part we would have preferred being able to accept a Single class instead of the whole org.springframework.cloud
. But, as you can see, there are too many classes to include to keep it maintenable over time.
So to sum-up:
* Opt-in configuration can be already implemented via a custom AutoConfigurationImportFilter
* It is not practical to use since most (all?) Spring Boot projects ignore this usecase
So could Spring Boot project considers opt-in AutoConfiguration
as an official use case and therefore make sure it is easy
to exclude an entire spring project?
Comment From: wilkinsona
@reda-alaoui Opt-in auto-configuration is already supported. To do so, omit @EnableAutoConfiguration
from your application. Typically this means that, rather than using @SpringBootApplication
, you use @SpringBootConfiguration
and @ComponentScan
instead. You can then use @ImportAutoConfiguration
to opt-in to specific auto-configuration classes.
Comment From: reda-alaoui
Hi @wilkinsona ,
I did acknowledge that opt-in was possible. The problem is that is not easy or maintenable.
In the case of Spring Cloud that would mean I have to use an @ImportAutoConfiguration
pulling at least 17 AutoConfiguration
classes. And for each new version of Spring Cloud
or related project, I would have to scan all possible spring.factories
to update my @ImportAutoConfiguration
.
This is not what I call easy or maintenable.
Comment From: reda-alaoui
Today there are 2 options: - pull all AutoConfiguration classes - pull AutoConfiguration classes one by one
I am looking for something in the middle. Something that would allow me to target easily the AutoConfiguration classes of one module. Some kind of AutoConfiguration group
?
Comment From: wilkinsona
Unlike almost every other Spring project, Spring Cloud builds on top of Spring Boot so I think you should consider the use of Spring Boot to be mandatory when you want to use Spring Cloud. Removing the dependency on Spring Boot is something that you'd have to raise with the Spring Cloud team.
I can't speak for the Spring Cloud team, but I imagine that they have used separate auto-configuration classes as they are separate pieces of functionality. Unfortunately, it's not clear to me how they could be grouped together in a way that would make sense for different users who aren't comfortable with using the classpath as a signal for what should and should not be auto-configured. I think it's highly likely that different users will want different grouping to meet their specific needs. Unfortunately, satisfying all of those needs would lead to a combinatorial explosion of groups. IIRC, @dsyer has done some experimental work in this area which he may be able to link us to.
If you'd like to pursue this, I'd recommend raising it with the Spring Cloud team to see if their auto-configuration needs to be as fine-grained as it currently is. Depending on what comes of that discussion we can then re-open this issue or open other more focussed issues if needed. You may also be interested in the experimental efforts in the Spring Fu project.
Comment From: reda-alaoui
@wilkinsona IMO this issue should be discussed in Spring Boot. Today it is about Spring Cloud. But it looks like building official Spring solutions on top of Spring Boot is not going to stop.
Unlike almost every other Spring project, Spring Cloud builds on top of Spring Boot
As you said, there are probably other Spring official projects that are built or will be built on top of Spring Boot. So again, I think this is the right place for this discussion.
Unfortunately, it's not clear to me how they could be grouped together in a way that would make sense for different users who aren't comfortable with using the classpath as a signal for what should and should not be auto-configured
Since there is at most one spring.factories
per jar, each spring.factories
could be identified as a group? The group would be only an id allowing opt-in users to pull all AutoConfigurations of one module using this id.
This is already what I have to do in a cumbersome way if I use @ImportAutoConfiguration. I have to scan manually each spring.factories
, so the groups are already naturally there in the wild.
Comment From: philwebb
I think it's unlikely that we'll be able to add support for this. The current setup quite intentionally tries to separate the contribution of auto-configuration classes (the spring.factories
entries) from the conditions that determine when they apply (usually @ConditionalOnClass
).
Even if we had something like an @AutoConfigureGroup
annotation, it's not clear to me where we'd apply it. Perhaps it's more obvious for Spring Clould projects, but for our own auto-configuration classes it's quite hard to come up with groups that would be generally useful to many users. It would also be a large investment of time for us to try an come up with these categories.
I think the current setup serves the majority of our users quite well. They can either use auto-configuration or they can use traditional @Enable...
annotations. Perhaps the real problem here is that Spring Clould doesn't provide @EnableLoadBalancer
stle annotation or non auto-configuration base classes that can be used.