spring boot 启动流程详解

主启动类

@SpringBootApplication
@MapperScan("com.example.mapper")
public class StableBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(StableBootApplication.class,args);
    }
}

SpringApplication类中有个静态run()方法,最终执行如下:

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

显然 分为两部分

  1. 实例化(new) SpringApplication。
  2. 执行run()方法。

阅读 SpringApplication类的构造函数
在这里插入图片描述

实例化 SpringApplication
获取并且设置应用类型(重要)

应用类型有三种:

  1. NONE:顾名思义,什么都没有,正常流程走,不额外的启动web容器,比如Tomcat。
  2. SERVLET:基于servlet的web程序,需要启动内嵌的servletweb容器,比如Tomcat。(常用)
  3. REACTIVE:基于reactive的web程序,需要启动内嵌reactiveweb容器,作者不是很了解,不便多说

源码如下:

static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
        return REACTIVE;
    } else {
        String[] var0 = SERVLET_INDICATOR_CLASSES;
        int var1 = var0.length;

        for(int var2 = 0; var2 < var1; ++var2) {
            String className = var0[var2];
            if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                return NONE;
            }
        }

        return SERVLET;
    }
}
获取并且设置初始化器以及监听器

初始化器以及监听器 调用的方法都是 getSpringFactoriesInstances(类型Type)。
最终逻辑是 从 从类路径META-INF/spring.factories中 加载 初始化器以及监听器 。
初始化器(ApplicationContextInitializer): 初始化某些 IOC容器刷新之前的组件。
监听器(ApplicationListener): 监听特定的事件 比如IOC容器刷新、容器关闭等。

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = this.getClassLoader();
    // 从 META-INF/spring.factories 中获取
    Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 根据名称实例化
    List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}
小结

SpringApplication的构建都是为了run()方法启动做铺垫,最重要的部分就是设置应用类型、设置初始化器、设置监听器。

注意: 初始化器和这里的监听器都要放置在spring.factories文件中才能在这一步骤加载,否则不会生效。因为此时IOC容器还未创建,所以即使将其注入到IOC容器中也是不会生效的。

在这里插入图片描述

执行run() 方法

上面分析了SpringApplication的构建过程,一切都做好了铺垫,现在到了启动的过程了。

获取、启动运行过程监听器

监听器(SpringApplicationRunListeners): 监听应用程序启动过程。

获取 loadFactoryNames()方法从spring.factories文件中获取值:

org.springframework.boot.SpringApplicationRunListener=
org.springframework.boot.context.event.EventPublishingRunListener

启动运行监听器

//执行starting()方法
listeners.starting(bootstrapContext, this.mainApplicationClass);
环境构建

加载系统配置以及用户的自定义配置(application.properties)

ConfigurableEnvironment environment =
this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);    
创建IOC容器
context = this.createApplicationContext();

在这里插入图片描述

很显然 我这里是 SERVLET 故创建的是 AnnotationConfigServletWebServerApplicationContext()。

这一步仅仅是创建了IOC容器,未有其他操作

刷新IOC容器的前置处理(重要)
this.prepareContext(bootstrapContext, context, environment, listeners, 
applicationArguments, printedBanner);
调用初始化器

从spring.factories取值的

将自定义的ApplicationContextInitializer放在META-INF/spring.factories中,在此时也是会被调用。

加载启动类,注入容器
两次广播事件
listeners.contextPrepared(context);
load(context, sources.toArray(new Object[0]));
刷新IOC容器(重要)

刷新容器完全是Spring的功能了,比如初始化资源,初始化上下文广播器等
tomcat内置应用服务器在此时启动

刷新IOC容器的后置处理
this.afterRefresh(context, applicationArguments);

默认为空,如果有自定义需求可以重写,比如打印一些启动结束日志等。

发出结束执行的事件
执行Runners
小结

在这里插入图片描述

未完待续…

springboot启动流程详解(清晰易懂)

springboot内置服务器tomca启动详解

spring boot源码解读

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/590150.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ICode国际青少年编程竞赛- Python-1级训练场-for循环练习

ICode国际青少年编程竞赛- Python-1级训练场-for循环练习 1、 for i in range(3):Dev.step(4)Dev.turnLeft()2、 for i in range(3):Dev.step(2)Dev.turnRight()Dev.step(2)Dev.turnLeft()3、 for i in range(3):Dev.step(2)Dev.turnRight()Dev.step(2)Dev.turnLeft()4、 for…

飞致云开源社区月度动态报告(2024年4月)

自2023年6月起&#xff0c;中国领先的开源软件公司FIT2CLOUD飞致云以月度为单位发布《飞致云开源社区月度动态报告》&#xff0c;旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况&#xff0c;以及当月主要的产品新版本发布、社区运营成果等相关信息。值得注意的是&…

VS下编译cuda代码MSB3721,返回代码255

查了一天才找到问题 将Generate Relocatable Device Code 设置为true

Kelpa-小型服务器开发框架分享

分享我的服务器开发框架--Kelpa&#xff1a; 这是一个由现代C编写的小型、学习性质的服务器框架&#xff0c;包含压缩&#xff0c;序列化&#xff0c;IO调度&#xff0c;Socket封装&#xff0c;文件配置&#xff0c;日志库等多个完整自研模块&#xff1a; 项目目前仍处于开发阶…

【银角大王——Django课程——用户表的基本操作】

Django课程——用户表的基本操作 模板的继承用户管理用户列表展示新建用户Django组件原始方法【麻烦&#xff0c;太原始】form组件modelform组件 使用modelsform组件编写添加页面 模板的继承 &#xff08;1&#xff09;先写一个页面模板————这个案例中的模板基本上就是一个…

无言:破局之道:顿悟+坚持——早读(逆天打工人爬取热门微信文章解读)

致无言 引言Python 代码第一篇 洞见 7年跟踪调查北京28个精英家庭&#xff1a;为什么顶尖大学孩子大多来自有钱家庭&#xff1f;第二篇 人民日报 来了&#xff01;新闻早班车要闻社会政策 结尾 控制你的情绪 否则它将控制你 在紧张的游戏中 控制情绪 避免冲动行为 是每个玩家的…

学习java的继承

1.什么是继承 java中提供了一个关键字&#xff0c;extends&#xff0c;可以让一个类与另一个类建立起父子关系。 例如 public class B extends A { --- } 在这里&#xff0c;我们称A类为父类&#xff08;也被称为基类或者超类&#xff09;B类称为子类&#xff08;或者是派生…

IDEA 申请学生许可证

如果你有学生账号&#xff0c;并且账号是 EDU 结尾的&#xff0c;可以申请 IDEA 的学生许可证。 有效期一年&#xff0c;完全免费。 在界面上输入邮件地址&#xff0c;然后单击按钮提交。 邮件中单击链接 JetBrains 会把一个带有链接的邮件发送到你的邮箱中。 单击邮箱中的…

【CTF MISC】XCTF GFSJ0512 give_you_flag Writeup(图像处理+QR Code识别)

give_you_flag 菜狗找到了文件中的彩蛋很开心&#xff0c;给菜猫发了个表情包 解法 图片的最后一帧好像闪过了什么东西。 用 Photoshop 打开&#xff0c;检查时间轴。 找到一张二维码&#xff0c;但是缺了三个角&#xff08;定位图案&#xff09;&#xff0c;无法识别。 找一…

C语言----贪吃蛇(补充)

各位看官好&#xff0c;我想大家应该已经看过鄙人的上一篇博客贪吃蛇了吧。鄙人在上一篇博客中只是着重的写了贪吃蛇的实现代码&#xff0c;但是前期的一些知识还没有具体的介绍&#xff0c;比如确认光标位置&#xff0c;句柄等。那么我这一篇博客就来补充上一篇博客所留下来的…

使用 Wireshark 实现 ARP 嗅探监听网络

前言 Wireshark是一个开源的网络协议分析工具&#xff0c;用于捕获和分析网络数据包。它可以在多个操作系统上运行&#xff0c;并提供了强大的功能和用户友好的界面。 通过Wireshark&#xff0c;用户可以捕获网络流量&#xff0c;并对其进行深入的分析。它支持多种协议的解析…

计算机网络-408考研

后续更新发布在B站账号&#xff1a;谭同学很nice http://【计算机408备考-什么是计算机网络&#xff0c;有什么特点&#xff1f;】 https://www.bilibili.com/video/BV1qZ421J7As/?share_sourcecopy_web&vd_source58c2a80f8de74ae56281305624c60b13http://【计算机408备考…

一文读懂Mysql数据库索引原理

MyISAM 存储引擎索引实现&#xff1a; MyISAM 索引文件&#xff08;磁盘上表对应.MYI&#xff09;和数据文件&#xff08;MYD&#xff09;是分离的&#xff08;非聚集&#xff09; InnoDB 存储引擎索引实现&#xff1a; InnoDB 索引实现&#xff08;聚集&#xff09; 表数据文…

Bert基础(二十)--Bert实战:机器阅读理解任务

一、机器阅读理解任务 1.1 概念理解 机器阅读理解&#xff08;Machine Reading Comprehension, MRC&#xff09;就是给定一篇文章&#xff0c;以及基于文章的一个问题&#xff0c;让机器在阅读文章后对问题进行作答。 在机器阅读理解领域&#xff0c;模型的核心能力体现在对…

【Cpp】类和对象#拷贝构造 赋值重载

标题&#xff1a;【Cpp】类和对象#拷贝构造 赋值重载 水墨不写bug 目录 &#xff08;一&#xff09;拷贝构造 &#xff08;二&#xff09;赋值重载 &#xff08;三&#xff09;浅拷贝与深拷贝 正文开始&#xff1a; &#xff08;一&#xff09;拷贝构造 拷贝构造函数&…

49. 【Android教程】HTTP 使用详解

在你浏览互联网的时候&#xff0c;绝大多数的数据都是通过 HTTP 协议获取到的&#xff0c;也就是说如果你想要实现一个能上网的 App&#xff0c;那么就一定会和 HTTP 打上交道。当然 Android 发展到现在这么多年&#xff0c;已经有很多非常好用&#xff0c;功能非常完善的网络框…

线性神经网络示例

通过5个条件判定一件事情是否会发生&#xff0c;5个条件对这件事情是否发生的影响力不同&#xff0c;计算每个条件对这件事情发生的影响力多大&#xff0c;写一个线性神经网络模型pytorch程序,最后打印5个条件分别的影响力。 一 在这个场景中&#xff0c;一个线性神经网络&…

ubuntu与redhat的不同之处

华子目录 什么是ubuntu概述 ubuntu版本简介桌面版服务器版 安装部署部署后的设置设置root密码关闭防火墙启用允许root进行ssh登录更改apt源安装所需软件 网络配置Netplan概述配置详解配置文件DHCP静态IP设置设置 软件安装方法apt安装软件作用常用命令配置apt源 deb软件包安装概…

浅拷贝与深拷贝面试问题及回答

1. 浅拷贝和深拷贝的区别是什么&#xff1f; 答&#xff1a; 浅拷贝&#xff08;Shallow Copy&#xff09;仅复制对象的引用而不复制引用的对象本身&#xff0c;因此原始对象和拷贝对象会引用同一个对象。而深拷贝&#xff08;Deep Copy&#xff09;则是对对象内部的所有元素进…

Git客户端(TortoiseGit)使用详解

1.概述 使用TortoiseGit比直接使用git 客户端和命令实现代码版本管理更为方便&#xff0c;本文根据实际使用情况作一些记录&#xff0c;特别是对于解决冲突的处理。 2.Git安装与配置 下载 Git - Downloads&#xff0c; 可参考Git安装步骤完成Git的安装与配置。 3.TortoiseG…