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

本文涉及的产品
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
简介: 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方法的启动流程到这里结束了.结论自己总结

图一

 

图二

 

相关文章
|
2天前
|
机器学习/深度学习 人工智能 自然语言处理
【人工智能】Foxmail邮箱在人工智能领域的应用方法及代码解析
Foxmail邮箱作为一款流行的邮件客户端软件,主要用于个人和企业的邮件收发、管理等功能。虽然它与人工智能(AI)技术有着潜在的融合点,但直接关于Foxmail邮箱在人工智能方面的应用代码并不是常规的讨论内容,因为邮箱客户端本身并不直接包含复杂的AI算法或代码。
112 58
|
21小时前
|
JavaScript Java Maven
毕设项目&课程设计&毕设项目:springboot+vue实现的在线求职管理平台(含教程&源码&数据库数据)
本文介绍了一款基于Spring Boot和Vue.js实现的在线求职平台。该平台采用了前后端分离的架构,使用Spring Boot作为后端服务
毕设项目&课程设计&毕设项目:springboot+vue实现的在线求职管理平台(含教程&源码&数据库数据)
|
1天前
|
NoSQL JavaScript 前端开发
SpringBoot+Vue实现校园二手系统。前后端分离技术【完整功能介绍+实现详情+源码】
文章介绍了如何使用SpringBoot和Vue实现一个校园二手系统,采用前后端分离技术。系统具备完整的功能,包括客户端和管理员端的界面设计、个人信息管理、商品浏览和交易、订单处理、公告发布等。技术栈包括Vue框架、ElementUI、SpringBoot、Mybatis-plus和Redis。文章还提供了部分源代码,展示了前后端的请求接口和Redis验证码功能实现,以及系统重构和模块化设计的一些思考。
SpringBoot+Vue实现校园二手系统。前后端分离技术【完整功能介绍+实现详情+源码】
|
4天前
|
Java Spring 容器
SpringBoot整合AOP实现打印方法执行时间切面
SpringBoot整合AOP实现打印方法执行时间切面
11 1
|
5天前
|
NoSQL 关系型数据库 MySQL
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
15 2
|
8天前
|
开发者 Python
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
32 1
|
8天前
|
开发者 Python
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
21 1
|
3天前
|
算法 安全 Java
深入解析Java多线程:源码级别的分析与实践
深入解析Java多线程:源码级别的分析与实践
|
5天前
|
Java UED
基于SpringBoot自定义线程池实现多线程执行方法,以及多线程之间的协调和同步
这篇文章介绍了在SpringBoot项目中如何自定义线程池来实现多线程执行方法,并探讨了多线程之间的协调和同步问题,提供了相关的示例代码。
31 0
|
5天前
|
Java Spring 容器
Java SpringBoot 中,动态执行 bean 对象中的方法
Java SpringBoot 中,动态执行 bean 对象中的方法
14 0

推荐镜像

更多