springboot启动流程之总体流程梳理

springboot的启动流程相当复杂,我们需要先把控整体流程,后面会有若干文章一一讲解springboot启动流程中的重要的细节,springboot的启动经过了一些一系列的处理,我们先看看整体过程的流程图
springboot启动流程

篇幅有限,我们这里先聊聊实例化SpringApplication的过程:

   /*** SpringApplication构造器* @param resourceLoader* @param primarySources*/public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.sources = new LinkedHashSet();this.bannerMode = Banner.Mode.CONSOLE;this.logStartupInfo = true;this.addCommandLineProperties = true;this.addConversionService = true;this.headless = true;this.registerShutdownHook = true;this.additionalProfiles = new HashSet();this.isCustomEnvironment = false;this.lazyInitialization = false;this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));//设置应用类型this.webApplicationType = WebApplicationType.deduceFromClasspath();//设置初始化器this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));//设置监听器this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));//获取主类class对象this.mainApplicationClass = this.deduceMainApplicationClass();}

获取应用程序的类型

首先是这个方法

this.webApplicationType = WebApplicationType.deduceFromClasspath();

我们进入这个方法就知道,首先判断是否响应式类型,如果不是就是一般的servlet类型的应用

    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 {//    private static final String[] SERVLET_INDICATOR_CLASSES =//    new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};//这里两个都是存在的类型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;}}

加载所有的初始化器

这里加载的初始化器是springboot自带初始化器,从 META-INF/spring.factories 配置文件中加载的,那么这个文件在哪呢?自带有2个,分别在源码的jar包的 spring-boot-autoconfigure 项目 和 spring-boot 项目里面各有一个

    /*** SpringApplication的getSpringFactoriesInstances* 这个是共用的方法* @param type 类型,一般都是接口类型* @param parameterTypes 参数类型,在获取初始化器的时候是一个空数组* @param args 初始化类* @return* @param <T> 返回的所有实例对象*/private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {//获取当前class加载器ClassLoader classLoader = this.getClassLoader();//加载所有的对象名称,全限定类名Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));//利用反射,初始化找的所有对象List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);//排序对象AnnotationAwareOrderComparator.sort(instances);return instances;}

加载配置文件,然后放到缓存中,缓存是一个map类型,key是当前类加载器,value是一个多值的map。

   /**** @param classLoader 类加载器* @return 返回是 key = v1,v2 多值map*/private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {//先从缓存中去取k-v,key是当前类加载器,value又是一个key -value,是一个MultiValueMap类型,一个key对应多个valueMultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);if (result != null) {return result;} else {try {//扫描所有META-INF/spring.factories的配置文件Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");MultiValueMap<String, String> result = new LinkedMultiValueMap();//遍历找的所有文件while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();UrlResource resource = new UrlResource(url);//转换成属性对象Properties properties = PropertiesLoaderUtils.loadProperties(resource);Iterator<?> it = properties.entrySet().iterator();//遍历文件中所有键值对 格式: key = v1,v2,v3while(it.hasNext()) {Map.Entry<?, ?> entry = (Map.Entry)it.next();String factoryTypeName = ((String)entry.getKey()).trim();String[] strings = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());int length = strings.length;for(int i = 0; i < length; ++i) {String factoryImplementationName = strings[i];result.add(factoryTypeName, factoryImplementationName.trim());}}}//缓存所有已经加载的 key = v1,v2,v3cache.put(classLoader, result);return result;} catch (IOException var13) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);}}}

我们讲接口名称com.xxx.xxx去缓存获取,然后得到一个实现接口的类名的列表,通过列表,实例化所有对象,下面我们看实例化的所有逻辑

   /*** 实例化spring.factories里面的实现类* @param type 类型* @param parameterTypes 类型参数,可以空* @param classLoader* @param args 参数 可以空* @param names 实例的名称* @return 实例化后的对象列表* @param <T>*/private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {List<T> instances = new ArrayList<>(names.size());Iterator<String> it = names.iterator();while(it.hasNext()) {String name = it.next();try {Class<?> instanceClass = ClassUtils.forName(name, classLoader);Assert.isAssignable(type, instanceClass);Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);T instance = BeanUtils.instantiateClass(constructor, args);instances.add(instance);} catch (Throwable var12) {throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);}}return instances;}

至此,为SpringApplication对象设置初始化器完毕

加载所有的监听器

代码如下:

        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

从代码也可以看出,和获取初始化器逻辑是一模一样的,这个就不多说了。

获取主类class对象

        this.mainApplicationClass = this.deduceMainApplicationClass();

该方法的主要遍历当前的堆栈信息,获取main方法的class类,方法详情信息

/*** 获取主类class对象* @return*/private Class<?> deduceMainApplicationClass() {try {StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();StackTraceElement[] var2 = stackTrace;int var3 = stackTrace.length;for(int var4 = 0; var4 < var3; ++var4) {StackTraceElement stackTraceElement = var2[var4];if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}} catch (ClassNotFoundException var6) {}return null;}

小结

创建SpringApplication对象,要设置一下属性信息

  • 设置应用类型
  • 设置初始化器
  • 设置监听器
  • 设置主类class对象

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

N叉树的前序与后续遍历(含两道leetcode题)

文章目录 589. N 叉树的前序遍历递归法迭代法 590. N 叉树的后序遍历递归法迭代法 589. N 叉树的前序遍历 589. N 叉树的前序遍历 给定一个 n 叉树的根节点 root &#xff0c;返回 其节点值的 前序遍历 。 n 叉树 在输入中按层序遍历进行序列化表示&#xff0c;每组子节点由…

CSP-S 2024 提高组初赛第一轮初赛试题及答案解析

完整试题&#xff0c;CSP-S-2024 CSP-S 2024 提高组初赛第一轮初赛试题及答案解析 一、 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 1 在 Linux 系统中&#xff0c;如果你想显示当前工作目录的…

哔哩哔哩自动批量删除抽奖动态解析篇(一)

本文的分析过程可能需要读者了解一点前后端数据交互和逆向分析的思路和基础&#xff0c;由于本人是新手&#xff0c;自己也处于摸索学习阶段&#xff0c;说的不对或者不好的地方敬请谅解。 一、删除动态流程分析 B站每条动态无论是转发他人的动态还是自己原创发布的动态都有一…

蓝桥杯1.小蓝的漆房

样例输入 2 5 2 1 1 2 2 1 6 2 1 2 2 3 3 3样例输出 1 2 import math import os import sys tint(input())#执行的次数 for j in range(t):n,kmap(int,input().split())#n为房间数 k为一次能涂的个数alist(map(int,input().split()))#以列表的形式存放房间的颜色maxvaluemath…

MySQL数据库的增删改查以及基本操作分享

1、登录MySQL数据库 首先找到你安装MySQL数据库的目录&#xff0c;然后在终端打开该目录&#xff0c;输入以下命令 mysql -u root -p然后输入密码就可以登录数据库了&#xff0c;看到如下页面就是登陆成功了 ***注意在终端操纵数据库时所有语句写完之后一定要加 &#xff1…

【基础算法总结】模拟篇

目录 一&#xff0c;算法介绍二&#xff0c;算法原理和代码实现1576.替换所有的问号495.提莫攻击6.Z字形变换38.外观数列1419.数青蛙 三&#xff0c;算法总结 一&#xff0c;算法介绍 模拟算法本质就是"依葫芦画瓢"&#xff0c;就是在题目中已经告诉了我们该如何操作…

【记录】大模型|Windows 下 Hugging Face 上的模型的通用极简调用方式之一

这篇文是参考了这篇&#xff0c;然后后来自己试着搭了一下&#xff0c;记录的全部过程&#xff1a;【翻译】Ollama&#xff5c;如何在 Ollama 中运行 Hugging Face 中的模型_ollama 导入 huggingface-CSDN 博客 另外还参考了这篇&#xff1a;无所不谈,百无禁忌,Win11 本地部署无…

【大模型】AutoDL部署AI绘图大模型Stable Diffusion使用详解

目录 一、前言 二、AI绘图大模型概述 2.1 AI绘图大模型介绍 2.2 AI绘图大模型特点 2.3 AI绘图大模型优势 三、主流的AI绘图大模型介绍 3.1 Midjourney 3.1.1 Midjourney介绍 3.1.2 Midjourney功能特点 3.1.3 Midjourney使用场景 3.2 Stable Diffusion 3.2.1 Stable …

【WRF运行第二期(Ubuntu)】ARWpost安装

WRF运行第二期&#xff1a;ARWpost安装 1 ARWpost介绍2 ARWpost安装2.1 ARWpos_V3安装前准备2.2 安装ARWpos2.3 修改Makefile文件2.4 修改configure.arwp文件2.5 生成可执行文件EXE2.6 修改namelist.ARWpost 参考 1 ARWpost介绍 ARWpost 是WRF模型后处理程序之一&#xff0c;用…

前端组件库Element UI 的使用

一、准备工作 1.确保安装了开发软件 VS Code&#xff08;此处可查阅安装 VS Code教程&#xff09;&#xff0c;确保相关插件安装成功 2.安装Node.js 和创建Vue项目&#xff08;此处可查阅安装创建教程&#xff09; 3.成功在VS Code运行一个Vue项目&#xff08;此处可查阅运行…

技术周总结 09.16~09.22 周日(架构 C# 数据库)

文章目录 一、09.16 周一1.1&#xff09;问题01&#xff1a; 软件质量属性中"质量属性场景"、"质量属性环境分析"、"质量属性效用树"、"质量属性需求用例分析"分别是什么&#xff1f;1.2&#xff09;问题02&#xff1a; 软件质量属性中…

MOS工作的三种状态及其分析——亚阈值区(截至区),深三极管区(又叫深线性区)和饱和区

1.MOS工作的三种状态及其分析——亚阈值区&#xff08;截至区&#xff09;&#xff0c;深三极管区&#xff08;又叫深线性区&#xff09;和饱和区。 1.1亚阈值区&#xff08;现代深亚微米工艺下的部分截至区&#xff09; 现代深亚微米工艺下&#xff0c;亚阈值区是指在Vgs小于阈…

WebLogic远程代码执行漏洞CVE-2020-14882

1.环境搭建 cd vulhub-master/weblogic/CVE-2020-14882 docker-compose up -d 2.登录后台 使用以下url绕过登录认证 主页 - base_domain - WLS 控制台http://47.121.211.205:7001/console/css/%252e%252e%252fconsole.portal 3.在目标服务器创建文件 http://47.121.211.…

Linux-gcc/g++

系列文章目录 C语言中的编译和链接 文章目录 系列文章目录一、编译过程gcc如何完成过程在这里涉及到一个重要的概念:函数库 二、动态库、静态库2.1 函数库一般分为静态库和动态库两种。 三、gcc选项gcc选项记忆 一、编译过程 具体过程在这一片c语言文章中讲解过:C语言中的编…

【记录】Excel|不允许的操作:合并或隐藏单元格出现的问题列表及解决方案

人话说在前&#xff1a;这篇的内容是2022年5月写的&#xff0c;当时碰到了要批量处理数据的情况&#xff0c;但是又不知道数据为啥一直报错报错报错&#xff0c;说不允许我操作&#xff0c;最终发现是因为存在隐藏的列或行&#xff0c;于是就很无语地写了博客&#xff0c;但内容…

STM32系统时钟

时钟为单片机提供了稳定的机器周期&#xff0c;从而使我们的系统能够正常的运行 时钟就像我们人的心脏&#xff0c;一旦有问题就整个都会崩溃 stm32有很多外设&#xff0c;但不是所有的外设都使用同一种时钟频率工作&#xff0c;比如我们的内部看门狗和RTC 只要30几k的频率就…

【PLW003】设备器材云端管理平台v1.0(SpringBoot+Mybatis+NodeJS+MySQL前后端分离)

设备器材云端管理平台是一种专为各种设备&#xff08;如教育行业中的实验设备、建筑行业中的施工设备等&#xff09;租赁或共享孵化的数字化管理工具&#xff0c;旨在融合数字化手段&#xff0c;提高各种设备器材的管理效率、 确保设备的安全稳定运行&#xff0c;并优化资源使用…

【Godot4.3】基于状态切换的游戏元素概论

提示 本文的设想性质比较大,只是探讨一种设计思路。完全理论阶段&#xff0c;不可行就当是闹了个笑话O(∩_∩)O哈哈~但很符合我瞎搞的气质。 概述 一些游戏元素&#xff0c;其实是拥有多个状态的。比如一个宝箱&#xff0c;有打开和关闭两个状态。那么只需要设定两个状态的图…

日志系统第五弹:同步日志器模块

日志系统第五弹&#xff1a;同步日志器模块 一、Logger类的设计1.功能2.如何打印日志3.设计 - - - 成员变量1.日志输出限制等级2.资源整合3.唯一标识4.互斥锁 4.设计 - - - 成员函数1.对外的日志打印接口2.抽象的日志实际落地接口3.其他接口 5.Logger类的框架 二、Logger类的实…

springboot地方特色美食分享系统-计算机毕业设计源码02383

摘要 本论文主要论述了如何使用SpringBoot技术开发一个地方特色美食分享系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述地方特色美食分享系统的当前背景以…