SpringBoot自动配置原理
注解分析
我们知道springBoot通过
@SpringBootApplication
注解实现自动配置,@SpringBootApplication
注解主要三个注解:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
1、
@SpringBootConfiguration
是对@Configuration
的封装,声明该类为配置类
2、@ComponentScan
包扫描注解,在源码中@ComponentScan
没有定义扫描路径,即默认扫描标注了该注解的类所在的路径(springBoot启动类所在包,这就是springBoot启动类需要放置在最外层的原因)
3、
@EnableAutoConfiguration
是启动自动配置的核心注解,该注解主要包含两个注解:@AutoConfigurationPackage
与
@Import
1)@AutoConfigurationPackage,该注解中通过
@Import(AutoConfigurationPackages.Registrar.class)
引入Registrar
类,该类只做了一件事,注册
org.springframework.boot.autoconfigure.AutoConfigurationPackages.BasePackages
,并保存被@AutoConfigurationPackage
标注的类所在的路包径供之后使用
2)
@Import
该注解引入了一个非常重要的类org.springframework.boot.autoconfigure.AutoConfigurationImportSelector
,该类可以帮助springBooot将所有满足条件的配置加载并创建到ioc容器中。也就是说springboot将对哪些类进行自动装配就取决于AutoConfigurationImportSelector
可以看到该类实现了各种Aware接口,分别表示在某个时刻将被回调。还实现了ImportSelector接口,该接口是spring引入外部文件的主要接口,我们只需要知道在容器启动过程中
DeferredImportSelectorGrouping
的getImports
会自动执行,该方法是自动配置逻辑的主要方法,也将是我们源码分析的入口方法。
源码部分
在
org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGrouping#getImports
方法中调用了
AutoConfigurationImportSelector$AutoConfigurationGroup#process
方法(我们可以看到该方法传入的参数就是AutoConfigurationImportSelector)
AutoConfigurationImportSelector$AutoConfigurationGroup#process方法中通过调用AutoConfigurationImportSelector的getAutoConfigurationEntry得到自动配置类
AutoConfigurationImportSelector#getAutoConfigurationEntry,该方法直接获取了所有需要自动配置的全限定名称
getAutoConfigurationEntry代码块1:从/META-INF/spring.factories获取配置类全限定类名(这个方法里面还有很多细节,感兴趣的朋友可以自行翻阅)
//该段代码,是从/META-INF/spring.factories文件中加载到自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
spring.factories
getAutoConfigurationEntry代码块2:排除部分配置类
//获取我们手动排除的自动配置类,比如我们配置动态数据源是需要排除默认的数据源配置类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
列如:
getAutoConfigurationEntry代码块3:过滤不满足条件的配置类
// 过滤,查看剩下的配置类是否满足自动配置的条件
configurations = filter(configurations, autoConfigurationMetadata);
// @ConditionalOnBean:仅仅在当前上下文中存在某个对象时,才会实例化一个Bean。
// @ConditionalOnClass:某个class位于类路径上,才会实例化-个Bean。
// @ConditionalOnExpression:当表达式为true的时候,才会实例化一个Bean。基于SpEL表达式的条件判断.
// @ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean。
// @ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化一个Bean.
我们随便打开一个自动配置类RabbitAutoConfiguration,我们可以看到一些带有
Conditional
(↑↑↑)字样的注解,这些注解就是所谓的条件,@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
是指在类路径中包含RabbitTemplate, Channel
这两个类就满足条件(说人话就是当你引入了Rabbitmq的相关jar包就满足条件);
@EnableConfigurationProperties注解:众所周知@EnableConfigurationProperties的作用是让@ConfigurationProperties注解生效,然而当前类中我们没有发现@ConfigurationProperties注解,其实它在@EnableConfigurationProperties(
RabbitProperties
.class)的RabbitProperties类中,来到这儿相信大家都知道其作用了,就是去核心配置文件中获取前缀为spring.rabbitmq的配置信息封装到RabbitProperties当中
总结
总结:springBoot通过
@SpringBootApplication
注解实现自动配置,该注解是一个组合注解主要包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan
三个注解,其中主要是@EnableAutoConfiguration
实现了自动配置,该注解通过@Import
引入了AutoConfigurationImportSelector
类,该类通过扫描/META-INF/spring.factories
配置文件获取自动配置类,然后将没有导入相关依赖的配置类进行排除,最后将剩下的配置类交由spring注入ioc容器。