【spring】springboot启动源码
创始人
2025-05-29 19:06:15
0次

说明

SpringBoot 版本 2.7.1

SpringApplication.run(),refresh()调用之前解析

  1. SpringApplication在构造方法时,就会读取META-INF/spring.factories的类,缓存到SpringFactoriesLoader中(这是Spring的SPI),注意这里的缓存不仅仅只有org.springframework.boot.autoconfigure.EnableAutoConfiguration,包括文件中所有key-value
    在这里插入图片描述
    在这里插入图片描述
    缓存是一个静态变量
    在这里插入图片描述

  2. SpringApplication第298行,通过SPI从META-INF/spring.factories获取org.springframework.boot.SpringApplicationRunListener的实现类并加载
    在这里插入图片描述
    通过构造器创建自定义RunListener实例
    在这里插入图片描述
    进入到自定义RunListener的构造方法
    在这里插入图片描述

  3. 第299行,通过spring.factories获取的所有SpringApplicationRunListener的实现类,并调用start方法
    在这里插入图片描述
    在这里插入图片描述

  4. SpringApplication第302行,创建spring环境配置类,默认环境变量实现类为ApplicationServletEnvironme
    在这里插入图片描述ApplicationServletEnvironment的抽象父类为AbstractEnvironment,他的成员变量MutablePropertySources propertySources是环境变量核心。包含了List> propertySourceList
    在这里插入图片描述
    PropertySource类结构
    在这里插入图片描述
    继续回到ApplicationServletEnvironment的构造方法创建,在默认调用抽象父类的构造中,执行了customizePropertySources(MutablePropertySources propertySources)方法
    在这里插入图片描述
    这个方法由ApplicationServletEnvironment的直接父类StandardServletEnvironment来实现,添加了两个默认的propertySource,再去调用StandardServletEnvironment的直接父类StandardEnvironment的customizePropertySources(MutablePropertySources propertySources)方法。再添加两个默认的propertySource,这里就包含了系统配置System.getProperties()和系统运行环境System.getenv()
    在这里插入图片描述
    以上只是prepareEnvironment方法的第341行逻辑,341行之后,还会添加一些propertySource、调用省略SpringApplicationRunListener的environmentPrepared方法等
    在这里插入图片描述
    完成spring环境配置类创建

  5. 创建IOC核心ApplicationContext,第305行
    context核心变量的核心包括:
    a. List beanFactoryPostProcessors
    b. ConfigurableEnvironment environment
    c. DefaultListableBeanFactory beanFactory
    在这里插入图片描述
    默认ApplicationContext的实现类是AnnotationConfigServletWebServerApplicationContext
    在这里插入图片描述
    它的间接父类是GenericApplicationContext,构造方法中初始化了beanFactory,这里与spring的ClassPathXmlApplicationContext有区别,ClassPathXmlApplicationContext是在refresh执行时才创建beanFactory,而GenericApplicationContext是在refresh之前
    以上为创建ApplicationContext逻辑。

  6. 进行ApplicationContext赋值处理,SpringApplication第307行prepareContext方法
    在这里插入图片描述
    进入prepareContext方法,这里赋值了environment、添加默认类到IOC容器(beanFactory的间接父类DefaultSingletonBeanRegistry中的singletonObjects,作为一级缓存)、设置循环依赖状态、添加默认BeanFactoryPostProcessor
    在这里插入图片描述
    调用SpringApplicationRunListener的contextPrepared、contextLoaded方法
    在这里插入图片描述
    在这里插入图片描述

  7. SpringApplication第308行,核心方法refreshContext(context);
    在这里插入图片描述
    调用context.refresh(),由AnnotationConfigServletWebServerApplicationContext的间接抽象父类AbstractApplicationContext来实现。

Context.refresh()调用方法解析

  1. AbstractApplicationContext第553行obtainFreshBeanFactory()
    在这里插入图片描述

这里的实现很简单,只是返回了beanFactory对象(如果context是用spring的ClassPathXmlApplicationContext,会在这里进行beanDefinition的构建,这里不做深入区别讨论)

在这里插入图片描述

  1. AbstractApplicationContext第556行,prepareBeanFactory

Prepare the bean factory for use in this context.

在这里插入图片描述
会默认添加一些beanPostProcess实现(比如ApplicationContextAwareProcessor,用来判断bean是否实现了各种Aware接口,如果实现了,ApplicationContextAwareProcessor会在postProcessBeforeInitialization执行回调)。
在这里插入图片描述

会默认注册一些单例bean到ioc容器(比如 environment、systemProperties、systemEnvironment等)。DefaultListableBeanFactory的父类DefaultSingletonBeanRegistry,里面的成员变量 Map singletonObjects,作为IOC容器用来存放单例对象,注册的单例bean会放在这里。
在这里插入图片描述

  1. AbstractApplicationContext第560行,postProcessBeanFactory

Allows post-processing of the bean factory in context subclasses.

在这里插入图片描述
由AnnotationConfigServletWebServerApplicationContext实现
在这里插入图片描述
super.postProcessBeanFactory(beanFactory)。会添加WebApplicationContextServletContextAwareProcessor到BeanPostProcessor

在这里插入图片描述
4. AbstractApplicationContext第564行,invokeBeanFactoryPostProcessors。
这个方法会执行springboot的自动装配核心逻辑

Invoke factory processors registered as beans in the context.

在这里插入图片描述
在这里插入图片描述
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 方法
第112行invokeBeanDefinitionRegistryPostProcessors
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
进入ConfigurationClassPostProcessor.processConfigBeanDefinitions方法
从beanFactory的beanDefinitionMap中,目前beanDefinitionMap的数据只有初始化时候加入的,如下
在这里插入图片描述

接着第287行 ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory),会依次遍历判断是否有@Configuration注解,启动类因为有@SpringBootApplication,它引用了@SpringBootConfiguration,而@SpringBootConfiguration又引用了@Configuration。把符合要求的BeanDefinition封装成BeanDefinitionHolder(第288行),然后加入到 List configCandidates 集合中

configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));

通过过滤放这里configCandidates集合只有启动类
在这里插入图片描述

第327行
Set candidates = new LinkedHashSet<>(configCandidates);
332行
构建了一个
ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);

processConfigBeanDefinitions方法第329-367行,递归遍历candidates集合,解析每一个BeanDefinitionHolder
第331行 parser.parse(candidates)
在这里插入图片描述
ConfigurationClassParser的parse方法,第175行
在这里插入图片描述
ConfigurationClassParser第206行,parse的重载方法
在这里插入图片描述
进入ConfigurationClassParser第225行,processConfigurationClass
第250行,开始处理@Configuration注解的类逻辑
在这里插入图片描述
进入ConfigurationClassParser,可以看到这里针对类上的注解做了很多判断,是否有@Component、@PropertySource、@ComponentScan、@Import注解等
在这里插入图片描述
先看ConfigurationClassParser-272行,当类上有@Component注解时,判断是否有内部类,再递归判断内部类是否有@Component
在这里插入图片描述

在这里插入图片描述
ConfigurationClassParser-第276行,判断是否有@PropertySources注解
在这里插入图片描述
ConfigurationClassParser-第442行开始,processPropertySource 方法
先判断@PropertySource的value是否为空(这是必要配置),然后加载value的值为Resource对象
ConfigurationClassParser-第463行,factory.createPropertySource(name, new EncodedResource(resource, encoding)),这里的factory默认是DefaultPropertySourceFactory
在这里插入图片描述

ConfigurationClassParser-第479行,进入DefaultPropertySourceFactory.createPropertySource方法

在这里插入图片描述
会创建并返回ResourcePropertySource对象
ResourcePropertySource的构造方法如下,通过getNameForResource(resource.getResource()) 和 *PropertiesLoaderUtils.loadProperties(resource)方法构造成 String name 和 Properties source,继续调用父类构造方法
在这里插入图片描述
最终ResourcePropertySource的顶层抽象类为PropertySource。构造完成后返回
在这里插入图片描述
回到ConfigurationClassParser-463行,将构造返回的propertySource,再调用
addPropertySource(propertySource)*方法

在这里插入图片描述
ConfigurationClassParser-479行,addPropertySource方法
判断environment的propertySources是否已经包含了此propertySource,如果没有包含,添加到propertySources中
第505-510行,是用来判断插入propertySources的位置
在这里插入图片描述
回到ConfigurationClassParser-280行,处理完了@PropertySources的逻辑,继续往下
ConfigurationClassParser-289行,开始处理@ComponentScan逻辑,进入296行componentScanParser.parse
在这里插入图片描述
ComponentScanAnnotationParser-68行parse方法,初始化ClassPathBeanDefinitionScanner类,处理了basePackages的包扫描路径等
在这里插入图片描述
直接看到ComponentScanAnnotationParser-128行,ClassPathBeanDefinitionScanner scanner.doScan(StringUtils.toStringArray(basePackages));
在这里插入图片描述
进入ClassPathBeanDefinitionScanner-272行的doScan方法,入参为scanBasePackages的值
从275行开始,遍历所有basePackages,276行,从basePackage的值开始扫描符合要求的bean,并封装成BeanDefinition
在这里插入图片描述
由父类ClassPathScanningCandidateComponentProvider实现findCandidateComponents 方法,第311行
再进入316行 scanCandidateComponents(basePackage);
在这里插入图片描述
ClassPathScanningCandidateComponentProvider第416行开始
获取classpath下符合basePackage的 .class路径。如这里的: classpath:org/hopehomi/**/*.class
在这里插入图片描述
获取到该路径下所有的 *.class路径
在这里插入图片描述

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...