SpringBoot启动原理——Run方法源码解析《课时十二》

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: SpringBoot启动原理——Run方法源码解析《课时十二》

SpringBoot启动运行项目是运行流程如上图所示


1. ApplicationStartingEvent`在运行开始时但在任何处理之前发送,除了侦听器和初始化程序的注册。

2. `ApplicationEnvironmentPreparedEvent`当`Environment`在上下文中使用的 已知但在创建上下文之前发送一个。

3. `ApplicationContextInitializedEvent`当`ApplicationContext`准备好并调用 Application Context Initializers 但在加载任何 bean 定义之前发送一个。

4. `ApplicationPreparedEvent`在刷新开始之前但在加载 bean 定义之后发送一个。

5. An`ApplicationStartedEvent`在上下文刷新之后但在调用任何应用程序和命令行运行程序之前发送。

6. `AvailabilityChangeEvent`在 with 之后立即发送一个`LivenessState.CORRECT`,表明应用程序被认为是活动的。

7. `ApplicationReadyEvent`在调用任何[应用程序和命令行运行程序](https://docs.spring.io/spring-boot/docs/2.4.13/reference/html/spring-boot-features.html#boot-features-command-line-runner)后发送一个。

8. `AvailabilityChangeEvent`在 with 之后立即发送一个`ReadinessState.ACCEPTING_TRAFFIC`,表示应用程序已准备好为请求提供服务。

9. 如果`ApplicationFailedEvent`启动时出现异常,则发送一个。

结论一:

  1. 1 判断项目类型
  2. 2 推断当前主类
  3. 3 设置监听器 获取上下文 全面接管SpringMvc配置
  4. 4 找到运行主类\

结论二:

.初始化SpringApplication 从spring.factories 读取listener ApplicationContextlnitializer


运行run方法


.读取 环境变量 配置信息....


.创建springApplication上下文:ServletWebServerApplicationContext


预初始化上下文:读取启动类


.调用refresh 加载Ioc容器 加载所有的自动配置类 创建servlet容器


在这个过程中springboot会调用很多监听器对外进行扩展

package com.spring.springboot0907web;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//深入源码
@SpringBootApplication
public class Springboot0907WebApplication {
    public static void main(String[] args) {
        //调用  SpringApplication.run 来启用
        SpringApplication.run(Springboot0907WebApplication.class, args);
    }
}
 public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

上面的代码不做介绍重点是今天要讲的Run方法:在这个方法中他要运行很多信息:

用户进入到Run方法中如下面的图所示

 public ConfigurableApplicationContext run(String... args) {
        long startTime = System.nanoTime();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
            }
            listeners.started(context, timeTakenToStartup);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var12) {
            this.handleRunFailure(context, var12, listeners);
            throw new IllegalStateException(var12);
        }

对上面的源码进行解析:

1 用来记录当前springBoot启动耗时 和记录启动时间

 long startTime = System.nanoTime();
 DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();

2 他是任何spring上下文的接口 所以他可以接收任何的ApplicationContext

ConfigurableApplicationContext context = null;

3   开启了Headless模式

this.configureHeadlessProperty()

4 去SpringFactories中读取     SpringApplicationRunListeners 的组件 又是用来发布监听器的

SpringApplicationRunListeners listeners = this.getRunListeners(args);
//点击getRunListeners(args)
 private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
    }

5 发布 ApplicationStartingEvent事件 在运行时发送

listeners.starting(bootstrapContext, this.mainApplicationClass);

6  根据命令行参数 实例一个 applicationArguments  对象

   ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

7  预初始化环境:读取变量 读取配置文件信息(基于监听器)

  ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);

插入一点:prepareEnvironment 介绍

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach((Environment)environment);
        listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
        DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
        Assert.state(!((ConfigurableEnvironment)environment).containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            EnvironmentConverter environmentConverter = new EnvironmentConverter(this.getClassLoader());
            environment = environmentConverter.convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }

1 根据webApplicationType 创建Environment 创建 就会读取: java环境 变量和系统环境变量

ConfigurableEnvironment environment = this.getOrCreateEnvironment();

2 将命令行参数读取环境变量中

 this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());

3 将PropertieSource的配置信息放在第一 位,因 为读取配置文件@PropertieSource优先级是最低的

ConfigurationPropertySources.attach((Environment)environment);

4 发布了ApplicationEnvironmentPreparedEvent 的监听器 读取了全局配置文件

  listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);

5 将所有spring .main开头的配置信息绑定SpringApplication

this.bindToSpringApplication((ConfigurableEnvironment)environment);

8 忽略beaninfo 的bean

this.configureIgnoreBeanInfo(environment);

9 打印Bean横幅

Banner printedBanner = this.printBanner(environment);

10 根据 webApplicationContext创建Spring上下文

context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);

11 准备应用上下文

  this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

12. 刷新应用上下文

this.refreshContext(context);

13 刷新完成后调          

this.afterRefresh(context, applicationArguments);

14 计算启动时间,JDK Duration类表示秒或纳秒时间间隔,

Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
//15. 打印启动日志
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
            }
            // 16. 开始执行监听器
            listeners.started(context, timeTakenToStartup);
            // 17. 从应用上下文中获取ApplicationRunner和CommandLinerRunner类型的Bean并调用他们的run方法
            this.callRunners(context, applicationArguments);
        } catch (Throwable var12) {
            // 处理异常
            this.handleRunFailure(context, var12, listeners);
            throw new IllegalStateException(var12);
        }
        try {
            Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
            // 18. 准备监听器
            listeners.ready(context, timeTakenToReady);
            // 19返回上下文
            return context;
        } catch (Throwable var11) {
            this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var11);
        }

今天的Run方法的启动流程到这里结束了.结论自己总结

图一

 

图二

 

目录
打赏
0
0
0
0
6
分享
相关文章
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
本期内容为「ximagine」频道《显示器测试流程》的规范及标准,我们主要使用Calman、DisplayCAL、i1Profiler等软件及CA410、Spyder X、i1Pro 2等设备,是我们目前制作内容数据的重要来源,我们深知所做的仍是比较表面的活儿,和工程师、科研人员相比有着不小的差距,测试并不复杂,但是相当繁琐,收集整理测试无不花费大量时间精力,内容不完善或者有错误的地方,希望大佬指出我们好改进!
59 16
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
解析静态代理IP改善游戏体验的原理
静态代理IP通过提高网络稳定性和降低延迟,优化游戏体验。具体表现在加快游戏网络速度、实时玩家数据分析、优化游戏设计、简化更新流程、维护网络稳定性、提高连接可靠性、支持地区特性及提升访问速度等方面,确保更流畅、高效的游戏体验。
54 22
解析静态代理IP改善游戏体验的原理
基于SpringBoot+Vue实现的留守儿童爱心网站设计与实现(计算机毕设项目实战+源码+文档)
博主是一位全网粉丝超过100万的CSDN特邀作者、博客专家,专注于Java、Python、PHP等技术领域。提供SpringBoot、Vue、HTML、Uniapp、PHP、Python、NodeJS、爬虫、数据可视化等技术服务,涵盖免费选题、功能设计、开题报告、论文辅导、答辩PPT等。系统采用SpringBoot后端框架和Vue前端框架,确保高效开发与良好用户体验。所有代码由博主亲自开发,并提供全程录音录屏讲解服务,保障学习效果。欢迎点赞、收藏、关注、评论,获取更多精品案例源码。
61 10
基于SpringBoot+Vue实现的家政服务管理平台设计与实现(计算机毕设项目实战+源码+文档)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
45 8
基于SpringBoot+Vue实现的家乡特色推荐系统设计与实现(源码+文档+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
56 8
基于SpringBoot+Vue实现的高校食堂移动预约点餐系统设计与实现(源码+文档+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
70 3
Spring&SpringBoot源码笔记整理 |Bean的加载流程二
昨天的文章里提到Bean的加载流程和如何获取bean,今天继续源码解读。还是老规矩,看着Bean加载的时序图进入主题。
346 0
Spring&SpringBoot源码笔记整理 |Bean的加载流程二
Spring&SpringBoot源码笔记整理 |Bean的加载流程一
本篇文章主要介绍Bean的加载流程,以及Spring是怎么解决循环依赖的问题。
155 0
Spring&SpringBoot源码笔记整理 |Bean的加载流程一
基于SpringBoot+Vue实现的冬奥会科普平台设计与实现(系统源码+文档+数据库+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
45 0
基于SpringBoot+Vue实现的大学生体质测试管理系统设计与实现(系统源码+文档+数据库+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
38 2

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等