【SpringBoot】SpringBoot源码解析第一章 SpringBoot的构造方法-CSDN博客
【SpringBoot】SpringBoot源码解析第二章 SpringBoot的run方法-CSDN博客
【SpringBoot】SpringBoot源码解析第三章 SpringBoot的自动化配置-CSDN博客
【SpringBoot】SpringBoot源码解析第四章 SpringBoot的bean接口-CSDN博客
【SpringBoot】SpringBoot源码解析第五章 SpringBoot的beanDefinition收集过程-CSDN博客
【SpringBoot】SpringBoot源码解析第六章 SpringBoot的getBean方法-CSDN博客
【SpringBoot】SpringBoot源码解析第七章 SpringBoot的感悟-CSDN博客
上一章我们分析了 SpringBoot 对象的构造方法,这一章我们来分析 SpringBoot 对象的 run 方法
参考源码:<spring.boot.version>2.3.12.RELEASE</spring.boot.version>
目录
1.1 createApplicationContext方法
1.3.1 invokeBeanFactoryPostProcessors方法
1.3.2 finishBeanFactoryInitialization方法
1、SpringApplication对象的run方法
点击进入 SpringApplication 对象的 run 方法,核心代码如下
// 创建上下文环境
context = this.createApplicationContext();
// 准备上下文环境,完成对上下文环境的初始化
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文环境,是自动装配的核心,也是debugger时执行最久的语句,重点研究对象
this.refreshContext(context);
我们逐个分析上面三个和上下文 context 相关的方法
1.1 createApplicationContext方法
createApplicationContext 方法通过反射创建了一个上下文环境 context,context 实现了BeanFactory 接口,我们可以把它看作是一个 Bean 工厂,Bean 工厂的职责就是生产 Bean
1.2 prepareContext方法
prepareContext 方法负责初始化 context 。第一章介绍了如何获取到初始化上下文环境相关的类,拿到这些类后就可以依次调用它们的 initialize 初始化方法,调用的入口是 this.applyInitializers(context)
1.3 refreshContext方法
refreshContext 方法顾名思义是用来刷新上下文环境的。刷新方法的调用链很长,跟踪refreshContext 方法找到 AbstractApplicationContext 的 refresh 方法
这个 refresh 方法是 Spring 装配 Bean 的核心,IOC 之道,就在其中
// 解析配置文件注解、生成beanDefinitions
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
// 完成bean工厂的初始化,并初始化所有剩余的非懒加载单例bean
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
refresh 方法涉及的内容比较多,重点分析 invokeBeanFactoryPostProcessors 方法和 finishBeanFactoryInitialization 方法,它们的职责分别是获取 Bean 生产原料和初始化部分单例 Bean
1.3.1 invokeBeanFactoryPostProcessors方法
跟踪 invokeBeanFactoryPostProcessors 方法找到 ConfigurationClassPostProcessor 类的processConfigBeanDefinitions方法
ConfigurationClassPostProcessor 类的 processConfigBeanDefinitions 方法会收集被 @Component 等注解标记的类的 BeanDefinition,BeanDefinition 封装了生产 Bean 的原料,里面包含了类全限定名等各种和类相关的信息
调用链:
-> processConfigBeanDefinitions
-> parser.parse(candidates);
-> parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
-> processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
-> doProcessConfigurationClass(configClass, sourceClass, filter);
-> this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
-> scanner.doScan(StringUtils.toStringArray(basePackages));
跟着调用链找到 doScan 方法,doScan 方法会扫描 @SpringBootApplication 注解内scanBasePackages 属性指定的包,未指定则默认扫描启动类所在目录下的包,收集包下所有 Bean 的 BeanDefinition,通俗来讲就是收集 Bean 原材料
1.3.2 finishBeanFactoryInitialization方法
跟踪 finishBeanFactoryInitialization 方法找到 DefaultListableBeanFactory 的 preInstantiateSingletons 方法,preInstantiateSingletons 方法调用 getBean 生成各种单例 Bean,在此处 debugger 可以看到 @Component、@Controller、@Service 等各种注解标记的类的生产过程,到这里 SpringBoot 应用基本算是初始化好了
2、总结
SpringApplication 的 run 方法将交给 Spring 托管的 Bean 都初始化好了(可延迟加载),并且提供了上下文环境供后续使用
本章只介绍了 run 方法的大体流程,Bean 具体的生成过程和 Bean 接口相关的内容都未做详细说明,以后有空补上
下一章我们分析 @SpringBootApplication 的自动装配功能