【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路径
在这里插入图片描述

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...