SpringBoot 启动流程

持续更新…

环境搭建

1、仓库地址

GITEE仓库地址

2、搭建步骤

准备工作:IDEA-2021、maven-3.3.9、JDK-8

①、pom.xml

创建普通的 maven 工程,修改 pom.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.micozone</groupId>
    <artifactId>SpringBoot-2.2.1.RELEASE</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <!--名字中包含spring-boot-starter的jar包主要作用为聚合其他jar包,并无代码-->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>

    </dependencies>

</project>

②、启动类

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

一、springApplication.run();

SpringApplication.run(); 主要有两步,第一步:new SpringApplication(); 第二步:springApplication.run(); 作为第一大部分

new SpringApplication();

new SpringApplication(); 中会对 springApplication 对象的一些属性赋值,主要有:
A:initializers = 所有 spring.factories 文件中 ApplicationContextInitializer 接口的实现类,其中 initializers 的类型为 List
B:listeners = 所有 spring.factories 文件中 ApplicationListener 接口的实现类,其中 listeners 的类型为 List
C:primarySource = [App.class]
其中 A 和 B 中,会调用 SpringFactoriesLoader.loadFactoryNames(); 其中第二次加载 ApplicationListener 的子类时,会使用到缓存(SpringFactoriesLoader 类有一个属性:cache,cache 的类型为:Map<ClassLoader, MultiValueMap<String, String>>),那是因为第一次加载 ApplicationListener 的子类时,已经把 spring.factories 文件中的所有数据存到 SpringFactoriesLoader.cache 中了。

1、getRunListeners(args); listeners.starting();

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
收集 spring.factories 文件中所有 SpringApplicationRunListener 接口的实现类,然后调用这些对象的 starting();
SpringBoot 2.2.1.RELEASE 包中的 spring.factories 文件中有 SpringApplicationRunListener=EventPublishingRunListener
EventPublishingRunListener使用到发布者模式,EventPublishingRunListener有一个属性 initialMulticaster,initialMulticaster 中收集了 springApplication 对象 listeners 属性的所有监听器,在调用不同的方法如 starting(); environmentPrepared(); 时,会通知相应的监听器执行 onApplicationEvent();

2、prepareEnvironment();

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
将所有环境信息封装到 configurableEnvironment 对象中(包括系统属性、系统环境变量、application.yml等),其中会执行 eventPublishingRunListener.environmentPrepared(environment);

3、createApplicationContext(); prepareContext(); refreshContext(); afterRefresh();

ConfigurableApplicationContext context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);

A、创建应用上下文

实际上创建的是 AnnotationConfigServletWebServerApplicationContext。
AnnotationConfigServletWebServerApplicationContext 的无参构造中会为两个重要的属性赋值:
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
其中 AnnotatedBeanDefinitionReader 注册的 beanDefinition 类型为 AnnotatedGenericBeanDefinition,ClassPathBeanDefinitionScanner 注册的 beanDefinition 类型为 ScannerGenericBeanDefinition。
并且 AnnotatedGenericBeanDefinition 的无参构造中会注册一个非常重要的 beanDefinition:ConfigurationClassPostProcessor。

B、应用上下文的准备工作

执行 applicationContextInitialization.initialize(context);
执行 eventPublishingRunListener.contextPrepared(context);
执行 beanDefinitionLoader.load(App.class);
执行 eventPublishingRunListener.contextLoaded(context);

C、应用上下文的刷新工作

应用上下文的刷新工作 作为第二大部分

D、应用上下文刷新后的工作

无代码逻辑

4、listeners.started(); callRunners(); listeners.running();

listeners.started(context);
callRunners(context, applicationArguments);
listeners.running(context);
A、eventPublishingRunListener.started();
B、调用所有实现 ApplicationRunner、CommandLineRunner 接口的 bean 对象的 run();
C、eventPublishingRunListener.running();

二、abstractApplicationContext.refresh();

首先获取到 applicationContext.beanFactory(); 作为每个方法的参数,其中 beanFactory 的实际类型为 DefaultListableBeanFactory

1、prepareBeanFactory(beanFactory);

TODO
beanFactory 的准备工作。
1、添加 bean 后置处理器:beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
2、添加忽略依赖注入的接口:beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
3、针对类型为接口的 bean,指定哪个实现类作为实际的 bean 对象:beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
4、注册单例 bean (直接添加到一级缓存中):beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());

2、invokeBeanFactoryPostProcessors(beanFactory);

调用 beanFactory 的后置处理器。
方法调用维度,先调用 beanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry); 该方法的主要作用就是注册 beanDefinition,或者修改 beanDefinition,其中执行的最重要的方法就是 configurationClassPostProcessor.postProcessBeanDefinitionRegistry(); 该方法会先收集 beanFactory.beanDefinitionNames 集合中含有 @configuration 注解的 beanName 对应的 mergedBeanDefinitions 集合中的 rootBeanDefinition 对象(一般只有启动类),该方法会针对每一个 rootBeanDefinition,调用 configurationClassParser.doProcessConfigurationClass(ConfigurationClass,SourceClass); 作为第三大部分;然后再调用 beanFactoryPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory); 该方法的主要作用就是修改 beanFactory。
对象处理维度,先处理 applicationContext.beanFactoryPostProcessors,然后再处理 beanFactory.beanDefinitionNames 中的 BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor 接口的实现类。

3、registerBeanPostProcessors(beanFactory);

将 beanDefinitionNames 中所有实现 beanPostProcessor 的 beanName,提前调用 getBean(beanName); 加载 bean 并放到 beanPostProcessors 集合中。

4、finishBeanFactoryInitialization(beanFactory);

完成 beanFactory 的 初始化,主要完成单例 bean 的加载工作:beanFactory.preInstantiateSingletons(); 作为第四大部分

三、configurationClassParser.doProcessConfigurationClass(ConfigurationClass,SourceClass);

1、@PropertySource

解析 @PropertySource,value 为 properties 文件数组,将 properties 文件中所有的键值对保存到 environment 对象中,可以通过 @Value(“${user.name}”) 取值。

2、@ComponentScan

通过 classPathBeandefinitionScanner.doScan(); 默认扫描当前包以及子包下含有 @Component 的类或接口,封装为 ScannerGenericBeanDefinition 对象,通过 beanFactory.registryBeanDefinition(); 注册到 beanDefinitionMap、beanDefinitionNames 中;
针对每一个扫描到的 beanDefinition,封装为指定对象作为参数继续调用 configurationClassParser.doProcessConfigurationClass(ConfigurationClass,SourceClass);

3、@Import

@Import

4、@Bean

针对每一个含有 @Bean 注解的方法,最终都会调用 registry.registerBeanDefinition(beanName, beanDefToRegister); 该方法会将返回值封装到 beanDefinitionMap、beanDefinitionNames 中。

四、beanFactory.preInstantiateSingletons();

遍历 beanDefinitionNames 集合,根据 beanName 获取 mergedBeanDefinitions 中的 rootBeanDefinition 对象,根据 rootBeanDefinition 判断 对象是否满足:非抽象类、是单例、非懒加载,如果都满足调用 getBean(beanName); 加载 bean。

1、getBean(beanName);

return doGetBean();

2、doGetBean();

A、getSingleton(beanName);

先查一级缓存(singletonObjects),查到返回,没查到判断 singletonsCurrentlyInCreation 集合是否包含 beanName,如果包含说明是第二次调用 getBean(beanName); 此时查询二级缓存(earlySingletonObjects),查到返回,没查到查三级缓存(singletonFactories),如果查到将值从三级缓存迁移至二级缓存并返回。
如果查到值,直接调用 getObjectForBeanInstance(); 逻辑结束。

B、getSingleton(beanName,ObjectFactory);

ObjectFactory 是函数式接口,getObject(); 中调用了createBean();

1、查一级缓存

查到直接返回,没查到继续往下进行。

2、singletonsCurrentlyInCreation.add(beanName);

将 beanName 添加到 singletonsCurrentlyInCreation 集合中。

3、createBean();

createBean(); 作为四.3部分

4、singletonsCurrentlyInCreation.remove(beanName);
5、将完整 bean 添一、删二三

C、getObjectForBeanInstance();

该方法无论如何都会被调用。
如果 beanName 以 & 开头或者不实现 FactoryBean 接口,直接返回 bean 实例。
如果 beanName 不以 & 开头并且实现 FactoryBean 接口,先根据 beanName 查缓存,缓存中没有再调用 getObject(); 获取真正的 bean,将 bean 放到缓存中,并返回。

3、createBean();

A、resolveBeforeInstantiation();

执行 beanPostProcessors 中实现 InstantiationAwareBeanPostProcessor 接口的 beanPostProcessor 的 postProcessBeforeInstantiation(beanClass, beanName); 如果方法的返回值不为null,直接return,
不执行 doCreateBean(beanName, …);

B、doCreateBean();

doCreateBean(beanName, …); 作为四.4部分

4、doCreateBean();

A、实例化 bean:createBeanInstance();

如果 beanDefinition.instanceSupplier 有值,直接调用 instanceSupplier.get(); 获取 bean 实例;
否则通过反射调用构造函数对象的 newInstance(); 实例化 bean。

B、属性赋值:populateBean();

在属性赋值前,判断 singletonsCurrentlyInCreation 是否包含 beanName,如果包含添三删二。
如果属性上有 @Resource,在执行 beanPostProcessors 中实现 InstantiationAwareBeanPostProcessor 接口的 beanPostProcessor 的 postProcessProperties(); 时,commonAnnotationBeanPostProcessor.postProcessProperties(); 逻辑中会通过反射对 @Resource 修饰的属性赋值:field.set(currentBean,otherBean); 其中 otherBean 会先查一级缓存,查询直接对属性赋值,如果没查到会调用 getBean(otherBean);

C、初始化 bean:initializeBean();

1、invokeAwareMethods();

如果 bean 实现指定 aware 接口,调用 setXXX();

2、beanPostProcessor.postProcessBeforeInitialization();

执行 beanPostProcessors 集合中每一个 beanPostProcessor 的 postProcessBeforeInitialization();
其中 commonAnnotationBeanPostProcessor.postProcessBeforeInitialization(); 中会判断是否存在含有 @PostConstruct 的方法,如果有,执行该方法。

3、invokeInitMethods();

如果 bean 实现 InitializingBean 接口,调用 afterPropertiesSet();

4、beanPostProcessor.postProcessAfterInitialization();

执行 beanPostProcessors 集合中每一个 beanPostProcessor 的 postProcessAfterInitialization();

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MicoZone

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值