44

The documentation states:

Developing auto-configuration and using conditions

If you work in a company that develops shared libraries, or if you work on an open-source or commercial library, you might want to develop your own auto-configuration. Auto-configuration classes can be bundled in external jars and still be picked-up by Spring Boot.

If I have annotations for everything else (even @AutoConfigureAfter or @AutoConfigureBefore annotations),

Why maintain a properties file to point to a class with an annotation?

1

5 Answers 5

51

Because we are not going to scan the world to figure out what auto-configuration classes exist in your project. For one, an auto-configuration is just a regular @Configuration class.

The way a Spring component is found is via explicit declaration or component scan but we need to know the list of auto-configuration classes way before we actually start the context.

Sign up to request clarification or add additional context in comments.

4 Comments

Can you please tell me which class will scan the spring.factories and do to instantiation?
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector and friends. Not that this is an internal component of Spring Boot you're not supposed to deal with.
@StephaneNicoll Since 2.7.0, Spring Boot introduced a new annotation @AutoConfiguration for auto-configuration classes. It seems that it is possible to scan the world to find all auto-configuration classes without spring.factories or org.springframework.boot.autoconfigure.AutoConfiguration.imports, however Spring Boot still relies on the files. I think it is because: 1. for compatibility reason; 2. the cost of scanning is relatively high. Is my understanding correct?
Not really, no. We don't scan the world, period. It's not about the cost but rather about detecting outside of the scope provided by the user. With a very large project, I can imagine this to be a bit costly though. It's still an opt-in mechanism.
2

all the entries in spring.factories are loaded by below method -

org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelector#loadFactoryNames

protected Collection<String> loadFactoryNames(Class<?> source) { return SpringFactoriesLoader.loadFactoryNames(source, getClass().getClassLoader()); } 

SpringFactoriesLoader belongs to the spring-core library see below screen shot

enter image description here

Comments

1

When SpringBoot app is starting, it will not scan all the classes in jars, So SpringBoot starter should specify which classes are auto-configured. For example, in spring-boot-2.0.4.RELEASE, it initializes like this:

@SpringBootApplication public class MyApplication { public static void main(String[] args) { //1. method run will call the construtor below SpringApplication.run(MyApplication.class, args); } } public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = deduceWebApplicationType(); //2. find all the classes whose key is ApplicationContextInitializer in spring.factories and initialize them setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); } ... private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates Set<String> names = new LinkedHashSet<>( //3. use current thread classcloader to load resources in the classpath SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } //SpringFactoriesLoader.java public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); // 3.1 first find the configuration file return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { ... try { Enumeration<URL> urls = (classLoader != null ? // public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; //4. spring.factories file is defined here classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); ... } 

Comments

0
  1. Improve the startup performance by creating a static list of candidates at compilation time.Just scan a static 'spring.factories' file, avoiding scanning a large number of class files in jars. Similar to @indexed in springframework 5.0. --META-INF/spring.components.
  2. Centralized configuration management, concise and compatible.

Comments

0

Good Read: https://blog.pchudzik.com/201903/spring-factories/

TL;DR

META-INF/spring.factories file is a special file picked up by the spring framework in which you can define how spring context will be customized. Documentation and spring-boot’s spring.factories.

But Why?

In the old days (before the spring-boot project) one had to configure context by hand. You had to be aware of what’s required for your application. What parts of the spring you’ll need, what database type you’ll be using, and for each of those prepare some XML configuration (java configuration was introduced in spring 3.x). With spring-boot things have changed. The troublesome and laborious process of configuring projects has been replaced by conventions and classpath scanning. Implementing such a mechanism can be easy but only if you deliver your framework as one huge blob that must be included with the project. Luckily (I’ve seen blobs…) spring-boot developers decided that they’ll ship highly specialized modules and you’ll be free to include only what’s necessary for you. With spring.factories file they are able to achieve exactly that. Each module can provide it’s own configuration which later will be merged and will comprise on spring context.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.