Skip to content

Commit 303979f

Browse files
committed
Merge branch '2.7.x'
2 parents 598eeb8 + 7d68b58 commit 303979f

File tree

17 files changed

+292
-28
lines changed

17 files changed

+292
-28
lines changed

buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,14 +16,19 @@
1616

1717
package org.springframework.boot.build.autoconfigure;
1818

19+
import java.io.BufferedReader;
1920
import java.io.File;
2021
import java.io.FileInputStream;
2122
import java.io.FileReader;
2223
import java.io.FileWriter;
2324
import java.io.IOException;
2425
import java.io.InputStream;
26+
import java.io.InputStreamReader;
2527
import java.io.Reader;
28+
import java.util.ArrayList;
29+
import java.util.Collections;
2630
import java.util.LinkedHashSet;
31+
import java.util.List;
2732
import java.util.Properties;
2833
import java.util.Set;
2934
import java.util.concurrent.Callable;
@@ -48,6 +53,8 @@
4853
*/
4954
public class AutoConfigurationMetadata extends DefaultTask {
5055

56+
private static final String COMMENT_START = "#";
57+
5158
private SourceSet sourceSet;
5259

5360
private File outputFile;
@@ -57,6 +64,12 @@ public AutoConfigurationMetadata() {
5764
.file((Callable<File>) () -> new File(this.sourceSet.getOutput().getResourcesDir(),
5865
"META-INF/spring.factories"))
5966
.withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName("spring.factories");
67+
getInputs()
68+
.file((Callable<File>) () -> new File(this.sourceSet.getOutput().getResourcesDir(),
69+
"META-INF/spring-boot/org.springframework.boot.autoconfigure.AutoConfiguration"))
70+
.withPathSensitivity(PathSensitivity.RELATIVE)
71+
.withPropertyName("org.springframework.boot.autoconfigure.AutoConfiguration");
72+
6073
dependsOn((Callable<String>) () -> this.sourceSet.getProcessResourcesTaskName());
6174
getProject().getConfigurations()
6275
.maybeCreate(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME);
@@ -86,11 +99,9 @@ void documentAutoConfiguration() throws IOException {
8699

87100
private Properties readAutoConfiguration() throws IOException {
88101
Properties autoConfiguration = CollectionFactory.createSortedProperties(true);
89-
Properties springFactories = readSpringFactories(
90-
new File(this.sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories"));
91-
String enableAutoConfiguration = springFactories
92-
.getProperty("org.springframework.boot.autoconfigure.EnableAutoConfiguration");
93-
Set<String> classNames = StringUtils.commaDelimitedListToSet(enableAutoConfiguration);
102+
Set<String> classNames = new LinkedHashSet<>();
103+
classNames.addAll(readSpringFactories());
104+
classNames.addAll(readAutoConfigurationsFile());
94105
Set<String> publicClassNames = new LinkedHashSet<>();
95106
for (String className : classNames) {
96107
File classFile = findClassFile(className);
@@ -109,6 +120,57 @@ private Properties readAutoConfiguration() throws IOException {
109120
return autoConfiguration;
110121
}
111122

123+
/**
124+
* Reads auto-configurations from META-INF/spring.factories.
125+
* @return auto-configurations
126+
*/
127+
private Set<String> readSpringFactories() throws IOException {
128+
File file = new File(this.sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories");
129+
if (!file.exists()) {
130+
return Collections.emptySet();
131+
}
132+
Properties springFactories = readSpringFactories(file);
133+
String enableAutoConfiguration = springFactories
134+
.getProperty("org.springframework.boot.autoconfigure.EnableAutoConfiguration");
135+
return StringUtils.commaDelimitedListToSet(enableAutoConfiguration);
136+
}
137+
138+
/**
139+
* Reads auto-configurations from
140+
* META-INF/spring-boot/org.springframework.boot.autoconfigure.AutoConfiguration.
141+
* @return auto-configurations
142+
*/
143+
private List<String> readAutoConfigurationsFile() throws IOException {
144+
File file = new File(this.sourceSet.getOutput().getResourcesDir(),
145+
"META-INF/spring-boot/org.springframework.boot.autoconfigure.AutoConfiguration");
146+
if (!file.exists()) {
147+
return Collections.emptyList();
148+
}
149+
// Nearly identical copy of
150+
// org.springframework.boot.autoconfigure.AutoConfigurationLoader.readAutoConfigurations
151+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
152+
List<String> autoConfigurations = new ArrayList<>();
153+
String line;
154+
while ((line = reader.readLine()) != null) {
155+
line = stripComment(line);
156+
line = line.trim();
157+
if (line.isEmpty()) {
158+
continue;
159+
}
160+
autoConfigurations.add(line);
161+
}
162+
return autoConfigurations;
163+
}
164+
}
165+
166+
private String stripComment(String line) {
167+
int commentStart = line.indexOf(COMMENT_START);
168+
if (commentStart == -1) {
169+
return line;
170+
}
171+
return line.substring(0, commentStart);
172+
}
173+
112174
private File findClassFile(String className) {
113175
String classFileName = className.replace(".", "/") + ".class";
114176
for (File classesDir : this.sourceSet.getOutput().getClassesDirs()) {

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring-boot/org.springframework.boot.autoconfigure.AutoConfiguration

Whitespace-only changes.

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,18 @@
2626
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2727
import org.springframework.context.annotation.Conditional;
2828
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.core.io.support.SpringFactoriesLoader;
2930

3031
/**
3132
* Indicates that a class provides configuration that can be automatically applied by
3233
* Spring Boot. Auto-configuration classes are regular
3334
* {@link Configuration @Configuration} with the exception that
3435
* {@literal Configuration#proxyBeanMethods() proxyBeanMethods} is always {@code false}.
3536
* <p>
37+
* They are located using the {@link AutoConfigurationLoader} and the
38+
* {@link SpringFactoriesLoader} mechanism (keyed against
39+
* {@link EnableAutoConfiguration}).
40+
* <p>
3641
* Generally auto-configuration classes are marked as {@link Conditional @Conditional}
3742
* (most often using {@link ConditionalOnClass @ConditionalOnClass} and
3843
* {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationExcludeFilter.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure;
1818

1919
import java.io.IOException;
20+
import java.util.ArrayList;
2021
import java.util.List;
2122

2223
import org.springframework.beans.factory.BeanClassLoaderAware;
@@ -54,13 +55,20 @@ private boolean isConfiguration(MetadataReader metadataReader) {
5455
}
5556

5657
private boolean isAutoConfiguration(MetadataReader metadataReader) {
57-
return getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());
58+
boolean annotatedWithAutoConfiguration = metadataReader.getAnnotationMetadata()
59+
.isAnnotated(AutoConfiguration.class.getName());
60+
return annotatedWithAutoConfiguration
61+
|| getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());
5862
}
5963

6064
protected List<String> getAutoConfigurations() {
6165
if (this.autoConfigurations == null) {
62-
this.autoConfigurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
63-
this.beanClassLoader);
66+
List<String> autoConfigurations = new ArrayList<>();
67+
autoConfigurations.addAll(
68+
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, this.beanClassLoader));
69+
autoConfigurations
70+
.addAll(new AutoConfigurationLoader().loadNames(AutoConfiguration.class, this.beanClassLoader));
71+
this.autoConfigurations = autoConfigurations;
6472
}
6573
return this.autoConfigurations;
6674
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -67,6 +67,7 @@
6767
* @author Andy Wilkinson
6868
* @author Stephane Nicoll
6969
* @author Madhura Bhave
70+
* @author Moritz Halbritter
7071
* @since 1.3.0
7172
* @see EnableAutoConfiguration
7273
*/
@@ -167,18 +168,23 @@ protected Class<?> getAnnotationClass() {
167168

168169
/**
169170
* Return the auto-configuration class names that should be considered. By default
170-
* this method will load candidates using {@link SpringFactoriesLoader} with
171+
* this method will load candidates using {@link AutoConfigurationLoader} with
172+
* {@link #getSpringFactoriesLoaderFactoryClass()}. For backward compatible reasons it
173+
* will also consider {@link SpringFactoriesLoader} with
171174
* {@link #getSpringFactoriesLoaderFactoryClass()}.
172175
* @param metadata the source metadata
173176
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
174177
* attributes}
175178
* @return a list of candidate configurations
176179
*/
177180
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
178-
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
179-
getBeanClassLoader());
180-
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
181-
+ "are using a custom packaging, make sure that file is correct.");
181+
List<String> configurations = new ArrayList<>();
182+
configurations.addAll(
183+
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
184+
configurations.addAll(new AutoConfigurationLoader().loadNames(AutoConfiguration.class, getBeanClassLoader()));
185+
Assert.notEmpty(configurations,
186+
"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring-boot/org.springframework.boot.autoconfigure.AutoConfiguration. If you "
187+
+ "are using a custom packaging, make sure that file is correct.");
182188
return configurations;
183189
}
184190

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure;
18+
19+
import java.io.BufferedReader;
20+
import java.io.IOException;
21+
import java.io.InputStreamReader;
22+
import java.net.URL;
23+
import java.nio.charset.StandardCharsets;
24+
import java.util.ArrayList;
25+
import java.util.Enumeration;
26+
import java.util.List;
27+
28+
import org.springframework.core.io.UrlResource;
29+
import org.springframework.core.io.support.SpringFactoriesLoader;
30+
import org.springframework.util.Assert;
31+
32+
/**
33+
* Loads the names of annotated classes, usually @{@link AutoConfiguration}.
34+
*
35+
* The names of the classes are stored in files named META-INF/spring-boot/{full qualified
36+
* name of the annotation}. Every line contains the full qualified class name of the
37+
* annotated class. Comments are supported using the # character.
38+
*
39+
* @author Moritz Halbritter
40+
* @see AutoConfiguration
41+
* @see SpringFactoriesLoader
42+
*/
43+
class AutoConfigurationLoader {
44+
45+
private static final String LOCATION = "META-INF/spring-boot/";
46+
47+
private static final String COMMENT_START = "#";
48+
49+
/**
50+
* Loads the names of annotated classes.
51+
* @param annotation annotation to load
52+
* @param classLoader class loader to use for loading
53+
* @return list of names of annotated classes
54+
*/
55+
List<String> loadNames(Class<?> annotation, ClassLoader classLoader) {
56+
Assert.notNull(annotation, "'annotation' must not be null");
57+
ClassLoader classLoaderToUse = decideClassloader(classLoader);
58+
String location = LOCATION + annotation.getName();
59+
Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
60+
List<String> autoConfigurations = new ArrayList<>();
61+
while (urls.hasMoreElements()) {
62+
URL url = urls.nextElement();
63+
autoConfigurations.addAll(readAutoConfigurations(url));
64+
}
65+
return autoConfigurations;
66+
}
67+
68+
private ClassLoader decideClassloader(ClassLoader classLoader) {
69+
if (classLoader == null) {
70+
return AutoConfigurationLoader.class.getClassLoader();
71+
}
72+
return classLoader;
73+
}
74+
75+
private Enumeration<URL> findUrlsInClasspath(ClassLoader classLoader, String location) {
76+
try {
77+
return classLoader.getResources(location);
78+
}
79+
catch (IOException ex) {
80+
throw new IllegalArgumentException("Failed to load autoconfigurations from location [" + location + "]",
81+
ex);
82+
}
83+
}
84+
85+
private List<String> readAutoConfigurations(URL url) {
86+
try (BufferedReader reader = new BufferedReader(
87+
new InputStreamReader(new UrlResource(url).getInputStream(), StandardCharsets.UTF_8))) {
88+
List<String> autoConfigurations = new ArrayList<>();
89+
String line;
90+
while ((line = reader.readLine()) != null) {
91+
line = stripComment(line);
92+
line = line.trim();
93+
if (line.isEmpty()) {
94+
continue;
95+
}
96+
autoConfigurations.add(line);
97+
}
98+
return autoConfigurations;
99+
}
100+
catch (IOException ex) {
101+
throw new IllegalArgumentException("Unable to load autoconfigurations from location [" + url + "]", ex);
102+
}
103+
}
104+
105+
private String stripComment(String line) {
106+
int commentStart = line.indexOf(COMMENT_START);
107+
if (commentStart == -1) {
108+
return line;
109+
}
110+
return line.substring(0, commentStart);
111+
}
112+
113+
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -60,9 +60,9 @@
6060
* and classes can be searched.
6161
* <p>
6262
* Auto-configuration classes are regular Spring {@link Configuration @Configuration}
63-
* beans. They are located using the {@link SpringFactoriesLoader} mechanism (keyed
64-
* against this class). Generally auto-configuration beans are
65-
* {@link Conditional @Conditional} beans (most often using
63+
* beans. They are located using the {@link AutoConfigurationLoader} and the
64+
* {@link SpringFactoriesLoader} mechanism (keyed against this class). Generally
65+
* auto-configuration beans are {@link Conditional @Conditional} beans (most often using
6666
* {@link ConditionalOnClass @ConditionalOnClass} and
6767
* {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).
6868
*

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelector.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
*
4545
* @author Phillip Webb
4646
* @author Andy Wilkinson
47+
* @author Moritz Halbritter
4748
*/
4849
class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector implements DeterminableImports {
4950

@@ -94,7 +95,10 @@ private Collection<String> getConfigurationsForAnnotation(Class<?> source, Annot
9495
}
9596

9697
protected Collection<String> loadFactoryNames(Class<?> source) {
97-
return SpringFactoriesLoader.loadFactoryNames(source, getBeanClassLoader());
98+
List<String> factoryNames = new ArrayList<>();
99+
factoryNames.addAll(SpringFactoriesLoader.loadFactoryNames(source, getBeanClassLoader()));
100+
factoryNames.addAll(new AutoConfigurationLoader().loadNames(source, getBeanClassLoader()));
101+
return factoryNames;
98102
}
99103

100104
@Override

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring-boot/org.springframework.boot.autoconfigure.AutoConfiguration

Whitespace-only changes.

0 commit comments

Comments
 (0)