SpringBoot 自动配置的原理是什么?
Spring
在启动的时候会自动扫描外部jar
包中的META-INF\spring.factories
,将文件中的配置类型信息加载到Spring
容器,并且执行类中定义的操作。对于外部的jar
包来说,只要遵循SpringBoot
的标准来,就能将自己的功能配置到SpringBoot
中。
SpringBoot 3.0
版本开始,自动配置包的路径就将META-INF\spring.factories
改成了META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports
SpringBoot 是如何实现自动配置的?
SpringBoot
自动配置主要是通过@EnableAutoConfiguratio
注解实现的,这个注解包含了@Import(AutoConfigurationImportSelector.class)
注解,作用是在启动的时候会自动扫描外部jar
的classPath
下的所有META-INF\spring.factories
(以SpringBoot 2.0
为例),根据文件中的指定配置类加载相应的Bean
自动配置。
@SpringBootApplication
我们来看看@SpringBootApplication
注解的源代码注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {// CODE...
}
@SpringBootConfiguration
:允许上下文额外注入的bean
或者导入其他配置类@EnableAutoConfiguration
:启动自动配置的机制@ComponentScan
:扫描被@Component/@Service/@Controller
注解的 bean,注解会默认扫描包下的所有 bean,可以自定义哪些不被扫描,例如TypeExcludeFilter, AutoConfigurationExcludeFilter
现在,我们重点关注@EnableAutoConfiguration
注解
@EnableAutoConfiguration
要了解该注解的工作机制,我们首先要从源码开始
源码:
...
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {// CODE...
}
@AutoConfigurationPackage
:负责注册主配置所在包以及子包到Spring
容器下@Import(AutoConfigurationImportSelector.class)
:导入自动配置选择器,负责加载和过滤所有自动配置类
AutoConfigurationImportSelector -- 自动配置导入选择器
1)AutoConfigurationImportSelector
的继承体制如下:
2)入口函数--selectImports()
功能:获取所有符合条件的类的全限定类名,并将这些类需要的加载到IOC
容器中
3)核心实现--加载自动配置类
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}// 1. 获取注解属性AnnotationAttributes attributes = getAttributes(annotationMetadata);// 2. 加载候选配置类List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 3. 去重configurations = removeDuplicates(configurations);// 4. 获取排除的配置Set<String> exclusions = getExclusions(annotationMetadata, attributes);// 5. 检查排除的类是否有效checkExcludedClasses(configurations, exclusions);// 6. 移除排除的配置configurations.removeAll(exclusions);// 7. 过滤配置(条件注解处理)configurations = getConfigurationClassFilter().filter(configurations);// 8. 触发事件fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);
}
关键点说明:
获取所有自动装配的配置类,读取META-INF\spring.factories
// 2. 加载候选配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations;
}
留下需要的配置类:
经过getCandidateConfigurations
读取META-INF\spring.factories
获取到所有自动装配的配置类之后,由于加载太多的配置类会影响Spring
容器的性能,因此需要对这些配置类进行排除过滤。
// 4. 获取排除的配置
Set<String> exclusions = getExclusions(annotationMetadata, attributes);// 5. 检查排除的类是否有效
checkExcludedClasses(configurations, exclusions);// 6. 移除排除的配置
configurations.removeAll(exclusions);// 7. 过滤配置(条件注解处理)
configurations = getConfigurationClassFilter().filter(configurations);
实操一遍:
1)判断自动配置是否打开
2)获取@EnableAutoConfiguration
注解中的exclude
和excludeName
...
public @interface EnableAutoConfiguration {// 排除特定的自动配置类,确保永远不会被应用Class<?>[] exclude() default {};// 排除特定的自动配置类名,确保永远不会被应用String[] excludeName() default {};}
效果如下
3)获取所有自动装配的配置类,读取META-INF\spring.factories
4)去重removeDuplicates(configurations)
通过哈希集合LinkedHashSet<>()
去掉重复的配置类
5)获取排除的配置类
比如我们在配置文件中写上:
spring:autoconfigure:exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
指 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
是要被排出的
说明已经排除成功
6)检查是否排除生效 -- checkExcludedClasses(configurations, exclusions)
7)移除要排除的配置类 -- configurations.removeAll(exclusions)
8)过滤出需要的配置类 -- 按需加载
9)触发自动导入事件
fireAutoConfigurationImportEvents(configurations, exclusions)
总结
SpringBoot
通过@EnableAutoConfiguration
注解自动装配,使用SpringFactoriesLoader
加载META-INF/spring.factories
中的自动装配的配置类。
end...