From 08022ba86efa294f77574bda07851901b6c2b520 Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Wed, 21 Sep 2022 15:56:35 -0500 Subject: [PATCH] Remove support for locating imports using spring.factories With this commit, loading `@AutoConfiguration`, `@ImportAutoConfiguration`, and `@ManagementContextConfiguration` classes is supported with `.imports` files only. Support for loading these classes with `spring.factories` is removed. Closes gh-29699 --- .../AutoConfigurationMetadata.java | 58 +++---------------- ...entContextConfigurationImportSelector.java | 8 +-- .../boot/autoconfigure/AutoConfiguration.java | 5 +- .../AutoConfigurationExcludeFilter.java | 10 +--- .../AutoConfigurationImportSelector.java | 26 +++------ .../EnableAutoConfiguration.java | 6 +- ...ImportAutoConfigurationImportSelector.java | 8 +-- .../AutoConfigurationImportSelectorTests.java | 5 +- .../context/annotation/ImportCandidates.java | 9 +++ 9 files changed, 35 insertions(+), 100 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java b/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java index 13dcd108d3f..5b3f29b62a3 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java @@ -23,15 +23,13 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.concurrent.Callable; +import java.util.stream.Collectors; import org.gradle.api.DefaultTask; import org.gradle.api.Task; @@ -43,13 +41,13 @@ import org.gradle.api.tasks.TaskAction; import org.springframework.asm.ClassReader; import org.springframework.asm.Opcodes; import org.springframework.core.CollectionFactory; -import org.springframework.util.StringUtils; /** * A {@link Task} for generating metadata describing a project's auto-configuration * classes. * * @author Andy Wilkinson + * @author Scott Frederick */ public class AutoConfigurationMetadata extends DefaultTask { @@ -60,10 +58,6 @@ public class AutoConfigurationMetadata extends DefaultTask { private File outputFile; public AutoConfigurationMetadata() { - getInputs() - .file((Callable) () -> new File(this.sourceSet.getOutput().getResourcesDir(), - "META-INF/spring.factories")) - .withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName("spring.factories"); getInputs() .file((Callable) () -> new File(this.sourceSet.getOutput().getResourcesDir(), "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports")) @@ -99,9 +93,7 @@ public class AutoConfigurationMetadata extends DefaultTask { private Properties readAutoConfiguration() throws IOException { Properties autoConfiguration = CollectionFactory.createSortedProperties(true); - Set classNames = new LinkedHashSet<>(); - classNames.addAll(readSpringFactories()); - classNames.addAll(readAutoConfigurationsFile()); + List classNames = readAutoConfigurationsFile(); Set publicClassNames = new LinkedHashSet<>(); for (String className : classNames) { File classFile = findClassFile(className); @@ -120,21 +112,6 @@ public class AutoConfigurationMetadata extends DefaultTask { return autoConfiguration; } - /** - * Reads auto-configurations from META-INF/spring.factories. - * @return auto-configurations - */ - private Set readSpringFactories() throws IOException { - File file = new File(this.sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories"); - if (!file.exists()) { - return Collections.emptySet(); - } - Properties springFactories = readSpringFactories(file); - String enableAutoConfiguration = springFactories - .getProperty("org.springframework.boot.autoconfigure.EnableAutoConfiguration"); - return StringUtils.commaDelimitedListToSet(enableAutoConfiguration); - } - /** * Reads auto-configurations from * META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. @@ -146,29 +123,18 @@ public class AutoConfigurationMetadata extends DefaultTask { if (!file.exists()) { return Collections.emptyList(); } - // Nearly identical copy of - // org.springframework.boot.context.annotation.ImportCandidates.load - try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) { - List autoConfigurations = new ArrayList<>(); - String line; - while ((line = reader.readLine()) != null) { - line = stripComment(line); - line = line.trim(); - if (line.isEmpty()) { - continue; - } - autoConfigurations.add(line); - } - return autoConfigurations; + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + return reader.lines().map(this::stripComment).filter((line) -> !line.isEmpty()) + .collect(Collectors.toList()); } } private String stripComment(String line) { int commentStart = line.indexOf(COMMENT_START); if (commentStart == -1) { - return line; + return line.trim(); } - return line.substring(0, commentStart); + return line.substring(0, commentStart).trim(); } private File findClassFile(String className) { @@ -182,12 +148,4 @@ public class AutoConfigurationMetadata extends DefaultTask { return null; } - private Properties readSpringFactories(File file) throws IOException { - Properties springFactories = new Properties(); - try (Reader in = new FileReader(file)) { - springFactories.load(in); - } - return springFactories; - } - } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextConfigurationImportSelector.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextConfigurationImportSelector.java index d54e7bc0845..107a5b71b59 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextConfigurationImportSelector.java @@ -29,7 +29,6 @@ import org.springframework.context.annotation.DeferredImportSelector; import org.springframework.core.OrderComparator; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; -import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; @@ -44,6 +43,7 @@ import org.springframework.util.StringUtils; * @author Phillip Webb * @author Andy Wilkinson * @author Moritz Halbritter + * @author Scott Frederick * @see ManagementContextConfiguration * @see ImportCandidates */ @@ -90,11 +90,7 @@ class ManagementContextConfigurationImportSelector implements DeferredImportSele } protected List loadFactoryNames() { - @SuppressWarnings("deprecation") - List factoryNames = new ArrayList<>( - SpringFactoriesLoader.loadFactoryNames(ManagementContextConfiguration.class, this.classLoader)); - ImportCandidates.load(ManagementContextConfiguration.class, this.classLoader).forEach(factoryNames::add); - return factoryNames; + return ImportCandidates.load(ManagementContextConfiguration.class, this.classLoader).getCandidates(); } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java index a8ad538d823..527106ec2f4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java @@ -30,16 +30,13 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AliasFor; -import org.springframework.core.io.support.SpringFactoriesLoader; /** * Indicates that a class provides configuration that can be automatically applied by * Spring Boot. Auto-configuration classes are regular * {@link Configuration @Configuration} with the exception that * {@literal Configuration#proxyBeanMethods() proxyBeanMethods} is always {@code false}. - *

- * They are located using {@link ImportCandidates} and the {@link SpringFactoriesLoader} - * mechanism (keyed against {@link EnableAutoConfiguration}). + * They are located using {@link ImportCandidates}. *

* Generally auto-configuration classes are marked as {@link Conditional @Conditional} * (most often using {@link ConditionalOnClass @ConditionalOnClass} and diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationExcludeFilter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationExcludeFilter.java index 20617ed1ee0..98c81a6414e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationExcludeFilter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationExcludeFilter.java @@ -17,13 +17,11 @@ package org.springframework.boot.autoconfigure; import java.io.IOException; -import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.boot.context.annotation.ImportCandidates; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; @@ -32,6 +30,7 @@ import org.springframework.core.type.filter.TypeFilter; * A {@link TypeFilter} implementation that matches registered auto-configuration classes. * * @author Stephane Nicoll + * @author Scott Frederick * @since 1.5.0 */ public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware { @@ -64,11 +63,8 @@ public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoad protected List getAutoConfigurations() { if (this.autoConfigurations == null) { - @SuppressWarnings("deprecation") - List autoConfigurations = new ArrayList<>( - SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, this.beanClassLoader)); - ImportCandidates.load(AutoConfiguration.class, this.beanClassLoader).forEach(autoConfigurations::add); - this.autoConfigurations = autoConfigurations; + this.autoConfigurations = ImportCandidates.load(AutoConfiguration.class, this.beanClassLoader) + .getCandidates(); } return this.autoConfigurations; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java index ac29dd0f481..dc9bfa03db2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java @@ -69,6 +69,7 @@ import org.springframework.util.StringUtils; * @author Stephane Nicoll * @author Madhura Bhave * @author Moritz Halbritter + * @author Scott Frederick * @since 1.3.0 * @see EnableAutoConfiguration */ @@ -168,36 +169,23 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector, } /** - * Return the auto-configuration class names that should be considered. By default - * this method will load candidates using {@link ImportCandidates} with - * {@link #getSpringFactoriesLoaderFactoryClass()}. For backward compatible reasons it - * will also consider {@link SpringFactoriesLoader} with - * {@link #getSpringFactoriesLoaderFactoryClass()}. + * Return the auto-configuration class names that should be considered. By default, + * this method will load candidates using {@link ImportCandidates}. * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return a list of candidate configurations */ protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { - @SuppressWarnings("deprecation") - List configurations = new ArrayList<>( - SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())); - ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add); + List configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()) + .getCandidates(); Assert.notEmpty(configurations, - "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you " + "No auto configuration classes found in " + + "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; } - /** - * Return the class used by {@link SpringFactoriesLoader} to load configuration - * candidates. - * @return the factory class - */ - protected Class getSpringFactoriesLoaderFactoryClass() { - return EnableAutoConfiguration.class; - } - private void checkExcludedClasses(List configurations, Set exclusions) { List invalidExcludes = new ArrayList<>(exclusions.size()); for (String exclusion : exclusions) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java index 4030ef5e8c4..6248937c657 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java @@ -32,7 +32,6 @@ import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.core.io.support.SpringFactoriesLoader; /** * Enable auto-configuration of the Spring Application Context, attempting to guess and @@ -61,9 +60,8 @@ import org.springframework.core.io.support.SpringFactoriesLoader; * and classes can be searched. *

* Auto-configuration classes are regular Spring {@link Configuration @Configuration} - * beans. They are located using {@link ImportCandidates} and the - * {@link SpringFactoriesLoader} mechanism (keyed against this class). Generally - * auto-configuration beans are {@link Conditional @Conditional} beans (most often using + * beans. They are located using {@link ImportCandidates}. Generally auto-configuration + * beans are {@link Conditional @Conditional} beans (most often using * {@link ConditionalOnClass @ConditionalOnClass} and * {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations). * diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelector.java index 89036c69c17..bd6eb6b3013 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelector.java @@ -32,7 +32,6 @@ import org.springframework.boot.context.annotation.ImportCandidates; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.ClassUtils; import org.springframework.util.LinkedMultiValueMap; @@ -46,6 +45,7 @@ import org.springframework.util.ObjectUtils; * @author Phillip Webb * @author Andy Wilkinson * @author Moritz Halbritter + * @author Scott Frederick */ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector implements DeterminableImports { @@ -96,11 +96,7 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec } protected Collection loadFactoryNames(Class source) { - @SuppressWarnings("deprecation") - List factoryNames = new ArrayList<>( - SpringFactoriesLoader.loadFactoryNames(source, getBeanClassLoader())); - ImportCandidates.load(source, getBeanClassLoader()).forEach(factoryNames::add); - return factoryNames; + return ImportCandidates.load(source, getBeanClassLoader()).getCandidates(); } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorTests.java index e22f3840ee2..7fb151a4ca6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorTests.java @@ -213,10 +213,7 @@ class AutoConfigurationImportSelectorTests { } private List getAutoConfigurationClassNames() { - List autoConfigurationClassNames = new ArrayList<>(); - ImportCandidates.load(AutoConfiguration.class, getClass().getClassLoader()) - .forEach(autoConfigurationClassNames::add); - return autoConfigurationClassNames; + return ImportCandidates.load(AutoConfiguration.class, getClass().getClassLoader()).getCandidates(); } private class TestAutoConfigurationImportSelector extends AutoConfigurationImportSelector { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/ImportCandidates.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/ImportCandidates.java index db7141de823..d7a43c0e020 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/ImportCandidates.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/annotation/ImportCandidates.java @@ -37,6 +37,7 @@ import org.springframework.util.Assert; * candidates. * * @author Moritz Halbritter + * @author Scott Frederick * @since 2.7.0 */ public final class ImportCandidates implements Iterable { @@ -57,6 +58,14 @@ public final class ImportCandidates implements Iterable { return this.candidates.iterator(); } + /** + * Returns the list of loaded import candidates. + * @return the list of import candidates + */ + public List getCandidates() { + return this.candidates; + } + /** * Loads the names of import candidates from the classpath. *