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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 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方法的启动流程到这里结束了.结论自己总结

图一

 

图二

 

相关文章
|
7天前
|
存储 缓存 算法
HashMap深度解析:从原理到实战
HashMap,作为Java集合框架中的一个核心组件,以其高效的键值对存储和检索机制,在软件开发中扮演着举足轻重的角色。作为一名资深的AI工程师,深入理解HashMap的原理、历史、业务场景以及实战应用,对于提升数据处理和算法实现的效率至关重要。本文将通过手绘结构图、流程图,结合Java代码示例,全方位解析HashMap,帮助读者从理论到实践全面掌握这一关键技术。
44 13
|
25天前
|
运维 持续交付 云计算
深入解析云计算中的微服务架构:原理、优势与实践
深入解析云计算中的微服务架构:原理、优势与实践
56 1
|
12天前
|
安全 Ubuntu Shell
深入解析 vsftpd 2.3.4 的笑脸漏洞及其检测方法
本文详细解析了 vsftpd 2.3.4 版本中的“笑脸漏洞”,该漏洞允许攻击者通过特定用户名和密码触发后门,获取远程代码执行权限。文章提供了漏洞概述、影响范围及一个 Python 脚本,用于检测目标服务器是否受此漏洞影响。通过连接至目标服务器并尝试登录特定用户名,脚本能够判断服务器是否存在该漏洞,并给出相应的警告信息。
131 84
|
1天前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
12 1
|
11天前
|
存储 Java 开发者
浅析JVM方法解析、创建和链接
上一篇文章《你知道Java类是如何被加载的吗?》分析了HotSpot是如何加载Java类的,本文再来分析下Hotspot又是如何解析、创建和链接类方法的。
|
23天前
|
负载均衡 网络协议 算法
Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式
本文探讨了Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式,以及软件负载均衡器、云服务负载均衡、容器编排工具等实现手段,强调两者结合的重要性及面临挑战的应对措施。
52 3
|
26天前
|
存储 供应链 算法
深入解析区块链技术的核心原理与应用前景
深入解析区块链技术的核心原理与应用前景
51 0
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
2月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
78 0
|
2月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
63 0

热门文章

最新文章

推荐镜像

更多