前言
- springboot相较于spring来说,一个比较大的特点就是Spring boot具有自动装配的功能,那么自动装配究竟是如何实现的呢?下文简单分析一下,水平有限,讲错了还请包容指正
源码分析
- 打开任何一个spring boot项目,都有一个主入口,就是@SpringBootApplication注解所在的类就是spring boot应用程序的主入口,所以我们从这个注解入手看。
@SpringBootApplication注解主要是由下面三个注解组成
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
第一个:@SpringBootConfiguration注解,该注解是由@Configuration注解和几个元注解组成,而@Configuration注解又是由@Component注解和几个原注解组成,结构如下面所示 ,所以说到底 @SpringBootConfiguration
所在的类就是一个组件,是一个配置类,该配置类会被实例化放到spring容器中
@SpringBootConfiguration
-- @Configuration
-- @Component
第二个:@EnableAutoConfiguration注解,这个注解字面意思就是开启自动配置,所以这个注解是实现自动配置的关键(重点)
@EnableAutoConfiguration
注解是由@AutoConfigurationPackage
注解和@Import(AutoConfigurationImportSelector.class)
组成,而@AutoConfigurationPackage
注解又是由@Import(AutoConfigurationPackages.Registrar.class)
组成,所以归根到底我们只需要弄懂两个@Import注解里面做了什么就可以,关于@Import注解的基本知识可以看@Import注解的使用,组成结构图如下
@EnableAutoConfiguration
-- @AutoConfigurationPackage
-- @Import(AutoConfigurationPackages.Registrar.class)
-- @Import(AutoConfigurationImportSelector.class)
对于@AutoConfigurationPackage
注解的作用其实就是获取到springboot主入口所在的包,并且注册一个Bean,就是我们的主入口所在的包名对象。以便后面知道包可以进行扫描注解。
这里重点是 @Import(AutoConfigurationImportSelector.class)
,我们一起看一下里面,这个@Import注解中的参数是ImportSelector接口的实现类,所以都会重写一个方法就是public String[] selectImports(AnnotationMetadata annotationMetadata)
该方法中的关键步骤就是:
//获取候选的配置
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry
方法中调用getCandidateConfigurations
方法来获取候选的配置
候选需要加载的类有两种:第一种是第三方自己自定义的starter,第二种是springboot官方提供的starter,这两个里面都有XXXAutoConfiguration类,都需要加载,所以首先SpringFactoriesLoader.loadFactoryNames
方法中将META-INF/spring.factories目录中所有第三方的starter中需要加载的类放到候选配置数集合configuration中,再通过 ImportCandidates.load
方法去META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports加载springboot自带的类,也放到候选配置集合configuration中。
小结:**`getCandidateConfigurations()`**方法做了两件事:第一件就是加载第三方stater中的XXXAutoConfiguration类,第二件就是再加载springboot自带的XXXAutoConfiguration类,全部都放到configuration集合中!!!
比如RedisAutoConfiguration类中
最后: getAutoConfigurationEntry
将符合条件的类名作为一个集合返回给selectImports
方法,selectImports
方法将这些类名全部实例化到容器中,自动装配就完成了。
流程图: