How does Spring Boot auto-configuration work?

When we annotate an application class with @EnableAutoConfiguration or @SpringBootApplication, SpringBoot tries to guess what beans are needed and configure them. Automatic configuration is based on the application’s CLASspath and custom beans. For example, if the classpath containing the tomcat – embedded. Jar, automatically configure TomcatServletWebServerFactory Bean. As follows:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}Copy the code

So how does Spring Boot’s auto-configuration work? Since the @SpringBootApplication annotation is also automatically configured via the @enableAutoConfiguration annotation, let’s look at the @EnableAutoConfiguration definition:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	......
}
Copy the code

The @enableAutoConfiguration definition is special only in these two annotations:

  • @AutoConfigurationPackage
  • @Import(AutoConfigurationImportSelector.class)

What does @autoConfigurationPackage do?

Let’s look at @autoConfigurationPackage, which is defined as follows:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
Copy the code

For @ Import (AutoConfigurationPackages. The Registrar. The class), literally, into a Registrar, The Registrar has realized ImportBeanDefinitionRegistrar interface, will launch a class in package storage package for automatic configuration. As follows:

/ * * * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
	 * configuration.
	 */
	static class Registrar implements ImportBeanDefinitionRegistrar.DeterminableImports {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
			register(registry, new PackageImport(metadata).getPackageName());
		}
Copy the code

@ Import ({AutoConfigurationImportSelector. Class}) do?

Back to @ Import ({AutoConfigurationImportSelector. Class}), the main method is selectImports:

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if(! isEnabled(annotationMetadata)) {return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
				annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}
Copy the code

This method does two things:

  • AutoConfigurationMetadataLoader. LoadMetadata (enclosing beanClassLoader), Load meta-INF /spring-autoconfigure-metadata.properties file and read the automatically configured META Data.
  • GetAutoConfigurationEntry (autoConfigurationMetadata annotationMetadata), load the meta-inf/spring. Factories file, get all the automatic configuration classes.

The meta-inf/spring – autoconfigure – metadata. The properties:

org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration.AutoConfigureAfter=org.springfra mework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration.Configuration= org.springframework.boot.autoconfigure.data.neo4j.Neo4jBookmarkManagementConfiguration.Configuration= org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration= org.springframework.boot.autoconfigure.kafka.KafkaAnnotationDrivenConfiguration.Configuration= org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration.ConditionalOnClass=org.influxdb.InfluxDB ......Copy the code

META-INF/spring.factories

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
......

Copy the code

All of these AutoConfiguration classes are components to add to the Spring container for automatic configuration.

An example describes the principle of automatic configuration

In the meta-INF /spring.factories file, you can see the Gson auto-configuration classes:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
......
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
......
Copy the code

You can see META Data automatically configured by Gson in meta-INF /spring-autoconfigure-metadata.properties. Specify that automatic configuration of gson is enabled only when the classpath contains com.google.gson.gson:

org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration.ConditionalOnClass=com.google.gson.Gson
Copy the code

For GsonAutoConfiguration, you can see @conditionalonClass (gson.class) corresponding to the Meta Data configuration, And @ EnableConfigurationProperties (GsonProperties. Class), is used to specify the Gson what configuration items can be configured in the file, such as application, yaml.

@Configuration
@ConditionalOnClass(Gson.class)
@EnableConfigurationProperties(GsonProperties.class)
public class GsonAutoConfiguration {... }Copy the code