源码调试以spring boot 1.5.8.release为例
Spring IOC容器初始化主要有以下几个步骤
1、资源定位:找到配置文件。
2、BeanDefinition载入和解析
3、BeanDefinition注册
4、实例化bean和依赖注入 (不在本篇讨论范围,该内容总结请看【十八】Spring IOC 总结之getBean主流程和各个扩展点总结)
而这一系列的操作种的前三步在SpringBoot中都是在AbstractApplicationContext#invokeBeanFactoryPostProcessors方法中完成的,该方法的源码导读请看以前写的这篇:【四】Spring源码分析之启动主流程---AbstractApplicationContext的refresh方法 只是对该方法做了一个简单介绍而已。
这个invokeBeanFactoryPostProcessors方法写的很恶心,里面是调用了ConfigurationClassPostProcessor的processConfigBeanDefinitions方法真正完成的资源定位、BeanDefinition载入和解析、BeanDefinition注册,该方法源码导读请看以前写的这篇:【八】Spring源码分析之扫描注册Bean----ConfigurationClassPostProcessor的processConfigBeanDefinitions方法
本篇主要是总结一下SpringBoot怎么做定位资源,主要的3中定位资源的方式
这里涉及到常规的Spring Boot项目中有3种定位方式:
1.扫主类(就是有注解@SpringBootApplication这个类)所在包的路径
2.SPI扩展机制实现的自动装配(比如各种starter)
3.@Import注解指定的类。
上面已经提到入口是ConfigurationClassPostProcessor的processConfigBeanDefinitions
这里面是调用ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)方法来做的定位
该方法中主要是两个事:
1.继续调用本类的其他parse方法做定位,最终的逻辑是在doProcessConfigurationClass方法中。
该方法包含了两种定位资源的方式
扫描springboot的有@SpringBootApplication注解的那个启动类所在的路径和对启动类的@Import注解的处理2.processDeferredImportSelectors方法加载默认的配置(对springboot项目来说这里就是自动装配的入口了)
一、ConfigurationClassParser#doProcessConfigurationClass方法
该方法就是扫描springboot的有@SpringBootApplication注解的那个启动类所在的路径
1.首先递归处理启动类的内部类,我们一般不会在启动类写内部类,就不debug这个了
2.对 @PropertySource 注解的属性配置进行处理,这个我也没有触发到
解析该注解并将该注解指定的properties配置文件中的值存储到Spring的 Environment中,Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
3.对 @ComponentScan 注解进行处理(该注解在@SpringBootApplication注解中)
1.扫描启动类所在的包,找到所有的@Component注解修饰的bean,并注册到BeanDefinitionMap中
这里就是从basePackage中扫描类并解析成ScannedGenericBeanDefinition然后注册
主要逻辑的实现入口在ClassPathBeanDefinitionScanner#doScan
2.检查该bean是否是ConfigurationClass(是否有configuration/component两个注解)
如果是,递归查找该类相关联的配置类。
(相关的配置类:比如@Configuration中的@Bean定义的bean。或者在有@Component注解的类上继续存在@Import注解)
4.递归处理启动类中的@Import,并加载该注解指定的配置类。
这里说一下,@SpringBootApplication注解中包含@EnableAutoConfiguration注解,
而@EnableAutoConfiguration注解
包含@Import(EnableAutoConfigurationImportSelector.class)和@AutoConfigurationPackage这两个注解是重点
5.处理启动类中的@ImportResource注解,这里没有触发
6.处理启动类中的@Bean注解,这里没有触发
7.处理启动类实现的接口方法,并没有触发
8.处理启动类的父类,并没有触发
二、processDeferredImportSelectors方法加载默认的配置
该方法就是通过启动类的@Import加载各个jar下META-INF/spring.factories的自动配置类并注册
对springboot项目来说这里就是自动装配的入口了
1.该方法里面会调用EnableAutoConfigurationImportSelector的父类AutoConfigurationImportSelector的selectImports方法
1.获取所有的自动配置类(META-INF/spring.factories中配置的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的类)
2.排除的自动装配类(springboot的主类上 @SpringBootApplication(exclude = {com.demo.starter.config.DemoConfig.class})指定的排除的自动装配类)
3.过滤掉不需要装配的类。过滤的逻辑有很多,比如我们常用的@ConditionXXX注解
4.返回需要自动配置类的全名
2.然后用ConfigurationClassParser#doProcessConfigurationClass方法讲这些自动配置类加载并注册