Skip to content

Commit eb5d92f

Browse files
committed
Exclude auto-configurations via property
Add `spring.autoconfigure.exclude` to control the list of auto-configuration classes to exclude via configuration. Merge the exclusions defined on the `@EnableAutoConfiguration` or `@SpringBooApplication` if any. Closes gh-2435
1 parent da60c94 commit eb5d92f

File tree

6 files changed

+87
-11
lines changed

6 files changed

+87
-11
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@
4444
* Auto-configuration tries to be as intelligent as possible and will back-away as you
4545
* define more of your own configuration. You can always manually {@link #exclude()} any
4646
* configuration that you never want to apply (use {@link #excludeName()} if you don't
47-
* have access to them). Auto-configuration is always applied after user-defined beans
48-
* have been registered.
47+
* have access to them). You can also exclude them via the
48+
* {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied
49+
* after user-defined beans have been registered.
4950
* <p>
5051
* The package of the class that is annotated with {@code @EnableAutoConfiguration} has
5152
* specific significance and is often used as a 'default'. For example, it will be used

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelector.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.util.ArrayList;
2121
import java.util.Arrays;
22+
import java.util.Collections;
2223
import java.util.LinkedHashSet;
2324
import java.util.List;
2425
import java.util.Set;
@@ -29,11 +30,14 @@
2930
import org.springframework.beans.factory.BeanFactoryAware;
3031
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3132
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
33+
import org.springframework.boot.bind.RelaxedPropertyResolver;
34+
import org.springframework.context.EnvironmentAware;
3235
import org.springframework.context.ResourceLoaderAware;
3336
import org.springframework.context.annotation.DeferredImportSelector;
3437
import org.springframework.core.Ordered;
3538
import org.springframework.core.annotation.AnnotationAttributes;
3639
import org.springframework.core.annotation.Order;
40+
import org.springframework.core.env.Environment;
3741
import org.springframework.core.io.ResourceLoader;
3842
import org.springframework.core.io.support.SpringFactoriesLoader;
3943
import org.springframework.core.type.AnnotationMetadata;
@@ -50,10 +54,12 @@
5054
*/
5155
@Order(Ordered.LOWEST_PRECEDENCE - 1)
5256
class EnableAutoConfigurationImportSelector implements DeferredImportSelector,
53-
BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware {
57+
BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware {
5458

5559
private ConfigurableListableBeanFactory beanFactory;
5660

61+
private Environment environment;
62+
5763
private ClassLoader beanClassLoader;
5864

5965
private ResourceLoader resourceLoader;
@@ -78,6 +84,7 @@ public String[] selectImports(AnnotationMetadata metadata) {
7884
Set<String> excluded = new LinkedHashSet<String>();
7985
excluded.addAll(Arrays.asList(attributes.getStringArray("exclude")));
8086
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
87+
excluded.addAll(getExcludeAutoConfigurationsProperty());
8188
factories.removeAll(excluded);
8289
ConditionEvaluationReport.get(this.beanFactory).recordExclusions(excluded);
8390
ConditionEvaluationReport.get(this.beanFactory).recordEvaluationCandidates(
@@ -94,6 +101,16 @@ public String[] selectImports(AnnotationMetadata metadata) {
94101
}
95102
}
96103

104+
private List<String> getExcludeAutoConfigurationsProperty() {
105+
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(this.environment,
106+
"spring.autoconfigure.");
107+
String[] value = resolver.getProperty("exclude", String[].class);
108+
if (value != null) {
109+
return Arrays.asList(value);
110+
}
111+
return Collections.emptyList();
112+
}
113+
97114
@Override
98115
public void setBeanClassLoader(ClassLoader classLoader) {
99116
this.beanClassLoader = classLoader;
@@ -110,4 +127,9 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
110127
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
111128
}
112129

130+
@Override
131+
public void setEnvironment(Environment environment) {
132+
this.environment = environment;
133+
}
134+
113135
}

spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
"description": "JMX name of the application admin MBean.",
3030
"defaultValue": "org.springframework.boot:type=Admin,name=SpringApplication"
3131
},
32+
{
33+
"name": "spring.autoconfigure.exclude",
34+
"type": "java.lang.Class[]",
35+
"description": "Auto-configuration classes to exclude."
36+
},
3237
{
3338
"name": "spring.batch.job.enabled",
3439
"type": "java.lang.Boolean",

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelectorTests.java

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.List;
2020

21+
import org.flywaydb.core.internal.util.StringUtils;
2122
import org.junit.Before;
2223
import org.junit.Test;
2324
import org.junit.runner.RunWith;
@@ -27,11 +28,13 @@
2728
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
2829
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
2930
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration;
3032
import org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration;
3133
import org.springframework.core.annotation.AnnotationAttributes;
3234
import org.springframework.core.io.DefaultResourceLoader;
3335
import org.springframework.core.io.support.SpringFactoriesLoader;
3436
import org.springframework.core.type.AnnotationMetadata;
37+
import org.springframework.mock.env.MockEnvironment;
3538

3639
import static org.hamcrest.Matchers.contains;
3740
import static org.hamcrest.Matchers.containsInAnyOrder;
@@ -54,6 +57,8 @@ public class EnableAutoConfigurationImportSelectorTests {
5457

5558
private final ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();
5659

60+
private final MockEnvironment environment = new MockEnvironment();
61+
5762
@Mock
5863
private AnnotationMetadata annotationMetadata;
5964

@@ -63,12 +68,13 @@ public class EnableAutoConfigurationImportSelectorTests {
6368
@Before
6469
public void configureImportSelector() {
6570
this.importSelector.setBeanFactory(this.beanFactory);
71+
this.importSelector.setEnvironment(this.environment);
6672
this.importSelector.setResourceLoader(new DefaultResourceLoader());
6773
}
6874

6975
@Test
7076
public void importsAreSelected() {
71-
configureExclusions(new String[0], new String[0]);
77+
configureExclusions(new String[0], new String[0], new String[0]);
7278
String[] imports = this.importSelector.selectImports(this.annotationMetadata);
7379
assertThat(
7480
imports.length,
@@ -82,7 +88,7 @@ EnableAutoConfiguration.class, getClass().getClassLoader())
8288
@Test
8389
public void classExclusionsAreApplied() {
8490
configureExclusions(new String[] { FreeMarkerAutoConfiguration.class.getName() },
85-
new String[0]);
91+
new String[0], new String[0]);
8692
String[] imports = this.importSelector.selectImports(this.annotationMetadata);
8793
assertThat(imports.length,
8894
is(equalTo(getAutoConfigurationClassNames().size() - 1)));
@@ -93,7 +99,7 @@ public void classExclusionsAreApplied() {
9399
@Test
94100
public void classNamesExclusionsAreApplied() {
95101
configureExclusions(new String[0],
96-
new String[] { VelocityAutoConfiguration.class.getName() });
102+
new String[] { VelocityAutoConfiguration.class.getName() }, new String[0]);
97103
String[] imports = this.importSelector.selectImports(this.annotationMetadata);
98104
assertThat(imports.length,
99105
is(equalTo(getAutoConfigurationClassNames().size() - 1)));
@@ -102,9 +108,22 @@ public void classNamesExclusionsAreApplied() {
102108
}
103109

104110
@Test
105-
public void bothExclusionsAreApplied() {
106-
configureExclusions(new String[] { VelocityAutoConfiguration.class.getName() },
107-
new String[] { FreeMarkerAutoConfiguration.class.getName() });
111+
public void propertyExclusionsAreApplied() {
112+
configureExclusions(new String[0], new String[0], new String[] {
113+
FreeMarkerAutoConfiguration.class.getName()});
114+
String[] imports = this.importSelector.selectImports(this.annotationMetadata);
115+
assertThat(imports.length,
116+
is(equalTo(getAutoConfigurationClassNames().size() - 1)));
117+
assertThat(ConditionEvaluationReport.get(this.beanFactory).getExclusions(),
118+
contains(FreeMarkerAutoConfiguration.class.getName()));
119+
}
120+
121+
@Test
122+
public void severalPropertyExclusionsAreApplied() {
123+
configureExclusions(new String[0], new String[0], new String[] {
124+
FreeMarkerAutoConfiguration.class.getName(), VelocityAutoConfiguration
125+
.class.getName()});
126+
108127
String[] imports = this.importSelector.selectImports(this.annotationMetadata);
109128
assertThat(imports.length,
110129
is(equalTo(getAutoConfigurationClassNames().size() - 2)));
@@ -114,7 +133,23 @@ public void bothExclusionsAreApplied() {
114133
VelocityAutoConfiguration.class.getName()));
115134
}
116135

117-
private void configureExclusions(String[] classExclusion, String[] nameExclusion) {
136+
@Test
137+
public void combinedExclusionsAreApplied() {
138+
configureExclusions(new String[] { VelocityAutoConfiguration.class.getName() },
139+
new String[] { FreeMarkerAutoConfiguration.class.getName() },
140+
new String[] { ThymeleafAutoConfiguration.class.getName() });
141+
String[] imports = this.importSelector.selectImports(this.annotationMetadata);
142+
assertThat(imports.length,
143+
is(equalTo(getAutoConfigurationClassNames().size() - 3)));
144+
assertThat(
145+
ConditionEvaluationReport.get(this.beanFactory).getExclusions(),
146+
containsInAnyOrder(FreeMarkerAutoConfiguration.class.getName(),
147+
VelocityAutoConfiguration.class.getName(),
148+
ThymeleafAutoConfiguration.class.getName()));
149+
}
150+
151+
private void configureExclusions(String[] classExclusion, String[] nameExclusion,
152+
String[] propertyExclusion) {
118153
given(
119154
this.annotationMetadata.getAnnotationAttributes(
120155
EnableAutoConfiguration.class.getName(), true)).willReturn(
@@ -123,6 +158,11 @@ private void configureExclusions(String[] classExclusion, String[] nameExclusion
123158
classExclusion);
124159
given(this.annotationAttributes.getStringArray("excludeName")).willReturn(
125160
nameExclusion);
161+
if (propertyExclusion.length > 0) {
162+
String value = StringUtils.arrayToCommaDelimitedString(propertyExclusion);
163+
this.environment.setProperty("spring.autoconfigure.exclude",
164+
value);
165+
}
126166
}
127167

128168
private List<String> getAutoConfigurationClassNames() {

spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ content into your application; rather pick only the properties that you need.
4545
spring.main.show-banner=true
4646
spring.main....= # see class for all properties
4747
48+
# AUTO-CONFIGURATION
49+
spring.autoconfigure.exclude= # comma-separated list of auto-configuration classes to exclude
50+
4851
# ADMIN ({sc-spring-boot-autoconfigure}/admin/SpringApplicationAdminJmxAutoConfiguration.{sc-ext}[SpringApplicationAdminJmxAutoConfiguration])
4952
spring.application.admin.enabled=false # enable admin features for the application
5053
spring.application.admin.jmx-name=org.springframework.boot:type=Admin,name=SpringApplication # JMX name of the application admin MBean

spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ report to the console.
602602

603603

604604

605-
[[using-boot-disabling-specific-auto-configutation]]
605+
[[using-boot-disabling-specific-auto-configuration]]
606606
=== Disabling specific auto-configuration
607607
If you find that specific auto-configure classes are being applied that you don't want,
608608
you can use the exclude attribute of `@EnableAutoConfiguration` to disable them.
@@ -619,7 +619,12 @@ you can use the exclude attribute of `@EnableAutoConfiguration` to disable them.
619619
}
620620
----
621621

622+
If the class is not on the classpath, you can use the `excludeName` attribute of
623+
the annotation and specify the fully qualified name instead. Finally, you can also
624+
control the list of auto-configuration classes to excludes via the
625+
`spring.autoconfigure.exclude` property.
622626

627+
TIP: You can define exclusions both at the annotation level and using the property.
623628

624629
[[using-boot-spring-beans-and-dependency-injection]]
625630
== Spring Beans and dependency injection

0 commit comments

Comments
 (0)