Spring Boot的自动配置是如何工作的?
当我们给应用类加上@EnableAutoConfiguration或者@SpringBootApplication注解时,Spring Boot会尝试推测需要哪些Bean,并配置这些Bean。自动配置会基于应用的classpath及自定义的Bean来配置。 比如, 如果classpath里包含tomcat-embedded.jar,会自动配置TomcatServletWebServerFactory Bean。如下:
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);
}
}
那么,Spring Boot的自动配置是如何工作的呢?因为@SpringBootApplication注解也是通过@EnableAutoConfiguration注解来完成自动配置的,所以来看一下@EnableAutoConfiguration的定义:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
......
}
@EnableAutoConfiguration定义的特殊之处也仅在这两个注解:
- @AutoConfigurationPackage
- @Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage做了什么?
先来看一下@AutoConfigurationPackage,定义如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
对于@Import(AutoConfigurationPackages.Registrar.class),从字面上理解,导入了一个Registrar,这个Registrar实现了ImportBeanDefinitionRegistrar接口,将启动类所在的package存储为自动配置的package。如下:
/**
* {@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());
}
@Import({AutoConfigurationImportSelector.class})做了什么?
回到@Import({AutoConfigurationImportSelector.class}),这个主要的方法是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());
}
这个方法做了两件事:
- AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader),加载 META-INF/spring-autoconfigure-metadata.properties文件,读取自动配置的Meta Data。
- getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata),加载 META-INF/spring.factories文件,获取所有自动配置类。
META-INF/spring-autoconfigure-metadata.properties:
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration.AutoConfigureAfter=org.springframework.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
......
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,\
......
这些所有的AutoConfiguration类都是要添加到Spring容器的组件,用于自动配置。
实例说明自动配置原理
以Gson的自动配置为例来说明下自动配置的原理, 在META-INF/spring.factories文件中可以看到Gson自动配置类:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
......
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
......
在META-INF/spring-autoconfigure-metadata.properties文件中可以看到Gson自动配置的Meta Data,指定当classpath中包含com.google.gson.Gson时才启动Gson的自动配置:
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration.ConditionalOnClass=com.google.gson.Gson
对于GsonAutoConfiguration,可以看到与Meta Data配置对应的@ConditionalOnClass(Gson.class),以及@EnableConfigurationProperties(GsonProperties.class), 用于指定Gson有哪些配置项可以在文件中配置,比如application.yaml.
@Configuration
@ConditionalOnClass(Gson.class)
@EnableConfigurationProperties(GsonProperties.class)
public class GsonAutoConfiguration {
......
}