SpringBoot 启动流程(基于2.2.6.RELEASE)
首先分为两部分
- 启动类上面的注解@SpringBootApplication
- main方法
public static void main(String[] args) {
SpringApplication.run(DemoSpringApplication.class, args);
}
-
从@SpringBootApplication这个注解看起
四个元注解不看,还剩下
@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
首先看@SpringBootConfiguration
点开发现被
@Configuration
注解了,并且成员方法proxyBeanMethods
已经被@AliasFor(annotation = Configuration.class)
注解,说明了@SpringBootConfiguration和@Configuration中的proxyBeanMethods互为别名(虽然它们的名字就是一致的,滑稽)。
那么就像注释提到的[Can be used as an alternative to the Spring`s standard @Configuration annotation so that configuration can be found automatically (for example in tests).],翻译过来就是可以用作Spring的标准@Configuration注释的替代,以便可以自动找到配置 (例如在测试中)。反正不知道都和@Configuration重复了,还有啥意义,不过注释中还提到了应用程序应该只包含一个@SpringBootConfiguration配置,大多数惯用的Spring Boot应用程序将从 @SpringBootApplication继承它。
再看@EnableAutoConfiguration
经过波澜不惊的@SpringBootConfiguration,还是迎来了@EnableAutoConfiguration这个大头,Spring中有一大串@Enable开头的注解,其实都是代表了一种能力,最终干活的还是@EnableXXX注解上面的@Import里面的Selector。
@EnableAutoConfiguration就是代表了开启了自动配置能力,啥意思呢,就是所有@Configuration的类会被扫到,并且把里面@Bean的方法转化为Bean放到spring容器中。然而不光是如此,@EnableAutoConfiguration配套的Selector叫AutoConfigurationImportSelector
,这个Selector里面还藏了亿点点小知识。下面都用[Selector]来代指[
AutoConfigurationImportSelector
]大家都知道SpringBoot有个减少配置文件的特点,是通过自动配置来实现的,可能还有小伙伴知道META-INF下面有个
spring.factories
,自动配置加载就是的这个文件下的bean定义,包含了很多常见的bean。但是大家有没有想过具体执行流程,还有比方说我明明没有用到es,但是spring.factories中有啊,并且还有很多我用不到的Config类,是不是浪费了?
首先看执行时机,前面说到了Selector被@Import带入了Spring容器中,并且看继承关系,这个Selector实现了ImportSelector
的selectImports
方法,那么好像答案呼之欲出了,直接给Selector的selectImports方法打上断点,奥里给,DEBUG启动,结果,并没有发生什么,?!,wtf,看来并不是这个方法被调用
后来经过尝试,发现了入口是Selector中内部类AutoConfigurationGroup
的process
方法。说下尝试的大致的思路就是getAutoConfigurationEntry
方法肯定会被调用,因为在这个方法读取了spring.factories
。
看到堆栈得知整个调用链路开端是ConfigurationClassPostProcessor
,这个类实现了BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法,不用我多说了吧,自己去百度refresh方法。
顺带说一句,把内部类AutoConfigurationGroup
暴露出去的途径是Selector实现了DeferredImportSelector
的getImportGroup
方法。
再看自动配置是否会冗余的问题,加载spring.factories的方法是Selector中的getAutoConfigurationEntry
方法,点进去看到有不少行,直接读取spring.factories执行链路是getAutoConfigurationEntry
getCandidateConfigurations
SpringFactoriesLoader.loadFactoryNames
我们先不拓展开原理,直接上DEBUG,发现刚开始读取完spring预置好的配置文件的数量是124个Config类Bean,但是经过Selector方法中
filter
方法逻辑后变成了23个。
大致原理是这些配置类上有@ConditionalOnClass
,以ElasticsearchAutoConfiguration
为例,我并没有导入es相关的依赖,所以不会实例化,就很nice