SpringBoot --- 自动配置的原理
-
-
- 1、关于SpringBoot自动配置
- 2、SpringBoot的自动配置的原理
-
- a.@SpringBootConfiguration
- b.@ComponentScan
- c.@EnableAutoConfiguration
-
- @AutoConfigurationPackage
- @Import({AutoConfigurationImportSelector.class})
-
1、关于SpringBoot自动配置
SpringBoot的自动配置就是当spring容器启动后,一些自动配置类(只是自动配置类,并不是当前组件配置到IOC容器当中,自动配置类通过@Conditional注解来按需配置)就自动装配的IOC容器中,不需要我们手动去注入,从而简化了开发,省去了繁琐的配置。
2、SpringBoot的自动配置的原理
一个SpringBoot工程想要成功运行,就必须拥有一个主程序类(被@SpringBootApplication 注解标识),而自动配置的相关工作就在 @SpringBootApplication这个注解上。
当我们进去到 @SpringBootApplication 注解的源码当中,可以发现它是一个复合注解,它是由 @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan 这三个注解组成
a.@SpringBootConfiguration
在@SpringBootConfiguration 源码中可以发现有 @Configuration,代表是一个配置类,说明主程序类也是一个配置类
b.@ComponentScan
指定扫描哪些组件,默认是扫描主程序所在的包以及其子包。
c.@EnableAutoConfiguration
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
}
@AutoConfigurationPackage
将指定的一个包下的所有组件导入到容器当中
自动配置包
在@AutoConfigurationPackage 注解中存在一个 @Import({Registrar.class}) 注解,自动配置包就是通过这个 Registrar 类的方法来完成的。
@Import({Registrar.class}) //给容器中导入一个组件
public @interface AutoConfigurationPackage {
//通过 Registrar 给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来,MainApplication 所在的包下
由于@AutoConfigurationPackage 是在 @EnableAutoConfiguration 中,所以@AutoConfigurationPackage 是标识在主程序类上,所以 metadata为主程序类
在Registrar中的 registerBeanDefinitions 方法,首先先获取到注解所标识的类,然后将这个类所在的包以及子包的名称放入到一个String数组当中,再将该String数组中的包的所有组件导入到容器当中
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
这也是为什么Spring容器启动后会自动导入 主程序所在的包及其子包中的所有组件
@Import({AutoConfigurationImportSelector.class})
该注解的大概流程就是:将 spring-boot-autoconfigure-x.x.x.jar包中 META-INF/spring.factories文件中的
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
getAutoConfigurationEntry(annotationMetadata); //给容器批量导入一些组件
selectImports()是AutoConfigurationImportSelector的核心函数,其核心功能就是获取spring.factories中EnableAutoConfiguration所对应的Configuration类列表,由@EnableAutoConfiguration注解中的exclude/excludeName参数筛选一遍,再由AutoConfigurationImportFilter类所有实例筛选一遍,得到最终的用于Import的configuration和exclusion。
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);//获取到所有需要导入到容器当中的组件
利用工厂加载 Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) //得到所有组件
从META-INF/spring.factories 位置来加载一个文件
默认扫描我们当前系统里面所有 META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.6.7.jar包里边也有 META-INF/spring.factories
configurations中一共有 133个组件,
可以发现,spring-boot-autoconfigure-2.6.7.jar包里边也有 META-INF/spring.factories, 而 spring.factories 的 EnableAutoConfiguration,正好有133条,而configurations中正好也有 133 条,所以configurations中读取到的内容,正好是 spring.factories 的 EnableAutoConfiguration 中的内容
文件里面写死了 SpringBoot 一启动就要给容器中加载的所有自动配置类
# 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,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
.........
最后按需开启自动配置项
虽然133个场景的所有自动配置启动的时候默认全部加载但是,按照条件装配规则,最终会按需配置,需要使用到 @Conditional 注解以及其子注解 ,按需加载