SpringBoot自动装配原理
本文是基于《Spring cloud Alibaba微服务原理与实战》(作者:谭锋)一书中关于SpringBoot的自动装配原理学习了解的。
1、springBoot自动装配的实现
通过IDEA创建一个SpringBoot工程后(或其他方式),就会在主启动类的上方发现@SpringBootApplication这个注解,其实这个注解就像是一个封装的方法。要进入到该注解中去,会发现有一个@EnableAutoConfiguration注解,见名知意,@EnableAutoConfiguration就是用来开启SpringBoot的自动装配的注解。
1 @SpringBootApplication
2 public class StaterApplication {
3
4 public static void main(String[] args) {
5 SpringApplication.run(StaterApplication.class, args);
6 }
7
8 }
9 @Target({ElementType.TYPE})
10 @Retention(RetentionPolicy.RUNTIME)
11 @Documented
12 @Inherited
13 @SpringBootConfiguration
14 @EnableAutoConfiguration
15 @ComponentScan(
16 excludeFilters = {@Filter(
17 type = FilterType.CUSTOM,
18 classes = {TypeExcludeFilter.class}
19 ), @Filter(
20 type = FilterType.CUSTOM,
21 classes = {AutoConfigurationExcludeFilter.class}
22 )}
23 )
24 public @interface SpringBootApplication {
25 ....
26 }
接着再进入@EnableAutoConfiguration,有两个重要的注解
①、@AutoConfigurationPackage : 作用是把使用了该注解的类所在包以及子包下的所有组件扫描到spring IOC容器中 这也是为什么在创建SpringBoot项目时,一定要把controller、service等都要与主启动类放在同一级目录的原因。
②、@Import({AutoConfigurationImportSelector.class}) 这个注解才是自动装配的重点,AutoConfigurationImportSelector这个类会实现配置类的导入,导入方式与@Configuration有一定的区别。
AutoConfigurationImportSelector实现了ImportSelector,它只有一个selectImports方法,返回一个String[]数组,这个数组中可以指定需要装配到IOC容器的类,当在@Import中导入一个ImportSelector的实现类之后,会把该实现类中返回的Class都装配到IoC容器中。和@Configuration不同的是,ImportSelector可以实现批量装配,并且还可以通过逻辑处理来实现Bean的选择性装配,也就是很具上下文环境来决定哪些类能够被IoC初始化。
1.1简单使用ImportSelector
首先创建两个类,要把这两个类装配到Ioc容器中
public class FirstClass{
}
public class SecondClass{
}
创建一个ImportSelector的实现类,把上述定义的两个Bean加入到String数组,意味着两个Bean会装配到Ioc中
自定义一个注解,模拟@EnableAutoConfiguration,通过@Import导入GpImportSelector.
创建一个启动类,在该类上使用@EnableAutoImport注解后,就可以从Ioc容器中取得FirstClass对象的实例。
这种实现方式相比@Import(*Configuration.class)的好处在于装配的灵活性,还可以实现批量装配,比如在G平ImportSelector还可以直接在String数组中定义多个Configuration类,由于一个配置代表的是某一个组件中批量的Bean声明,所以自动装配过程中只需要扫描到指定路径下的配置类即可。
2、自动装配原理分析
定位到AutoConfigurationImportSeletor中的selectImpots方法,他是ImportSelector的实现,该方法主要有两个功能:
①、AutoConfigurationMetadataLoader.loadMetadata从META-INFO/spring-autoconfigure-metadata.properties中加载自动装配的条件的元数据,就是满足条件的Bean才能够进行装配。
②、autoConfigurationEntry.getConfigurations()收集所有符合条件的配置类,完成自动装配
需要注意的是,AutoConfigurationImportSeletor中不执行selectImports方法,而是通过ConfigurationClassPostProcessor中的processConfigBeanDefinitions方法来扫描和注册所有的配置类的Bean,最终调用getAutoConfigurationEntry方法来获得所有需要自动装配的配置类。
以下是getAutoConfigurationEntry方法中几个重要的方法:
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);//获得@EnableAutoConfiguration注解的属性exclude、excludeName等
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);//获得候选的自动装配的配置类
configurations = this.removeDuplicates(configurations);//去除重复配置项
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);//根据@EnableAutoConfiguration注解的属性exclude等属性,把不需要自动装配的移除
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
总的来说就是,先获取所有的配置类,通过去重、exclude排除等操作,得到最终需要自动装配的配置类。
getCandidateConfigurations这个方法中使用到了SpringFactoriesLoader,会扫描classpath下的META-INFO/spring.factories文件,spring.factories文件中的数据以key=value形式存储,而SpringFactoriesLoader.loaderFactoryName会根据Key得到对应的value值,因此,key对应为EnableAutoConfiguration,Value是多个配置类,也就是getCandidateConfigurations返回的值。
省略。。。。。
另外还使用了许多@ConditionXXX的条件装配的注解
至此,自动装配的原理就分析完了,简单总结一下:
①、通过@Import(AutoConfigurationImportSelector.class),导入配置类,这里并不是单个配置类的导入
②、AutoConfigurationImportSelector实现了ImportSelector类,重写了selectImports方法,用于实现选择性的批量配置类的装配
③、通过Spring的SpringFactoryLoader机制,扫描classpath下的META/spring.factories文件,读取需要实现自动装配的配置类
④、通过条件筛选,把不符合的移除,最终实现自动装配