SpringBoot启动流程分析之创建SpringApplication对象(一)
SpringBoot启动流程分析之创建SpringApplication对象(一)
目录:
文章目录
- SpringBoot启动流程分析之创建SpringApplication对象(一)
- 1、SpringApplication的构造方法
- 1.1、推断应用程序类型
- 1.2、设置Initializers
- 1.3、设置Listener
- 1.4、推断main方法所在类
流程分析
1、SpringApplication的构造方法
来看一下在SpringApplication对象的构造方法中都做了哪些事。
public SpringApplication(Class<?>... primarySources) {this(null, primarySources);
}@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;//判断primarySources不能为空Assert.notNull(primarySources, "PrimarySources must not be null");//将primarySources放入SpringApplication的全局变量primarySources,Set集合中this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//从类路径中推断应用程序类型放到SpringApplication的全局变量webApplicationType this.webApplicationType = WebApplicationType.deduceFromClasspath();//从META-INF/spring.factories文件中获取ApplicationContextInitializer接口的实现类并利用反射创建对象返回放入SpringApplication的全局变量initializers,List集合中setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//同上,也是从META-INF/spring.factories文件中获取ApplicationListener接口的实现类并利用反射创建对象返回放入SpringApplication的全局变量listeners,List集合中setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//通过获取当前调用栈,找到入口方法main所在的类,放入SpringApplication的全局变量mainApplicationClass this.mainApplicationClass = deduceMainApplicationClass();
}
1.1、推断应用程序类型
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };private static final String WEBFLUX_INDICATOR_CLASS = "org."+ "springframework.web.reactive.DispatcherHandler";private static final String WEBMVC_INDICATOR_CLASS = "org.springframework."+ "web.servlet.DispatcherServlet";private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";static WebApplicationType deduceFromClasspath() {//ClassUtils.isPresent()从默认classloader中判断是否存在对应的类型if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {return WebApplicationType.REACTIVE;}for (String className : SERVLET_INDICATOR_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}}return WebApplicationType.SERVLET;
}
推断逻辑是:
先是判断默认的classloader中是否存在org.springframework.web.reactive.DispatcherHandler、且不存在org.springframework.web.servlet.DispatcherServlet、org.glassfish.jersey.servlet.ServletContainer,如果为true返回WebApplicationType.REACTIVE;
然后循环String数组,判断如果默认的classloader中是否不存在javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext,如果不存在,则认为不是web应用程序,返回WebApplicationType.NONE;
最后是返回WebApplicationType.SERVLET。
三种返回类型的解释如下:
1、WebApplicationType.NONE:不是web应用程序2、WebApplicationType.SERVLET:基于servlet的Web应用程序运行3、WebApplicationType.REACTIVE:响应式的web应用程序
1.2、设置Initializers
传入参数是class类型即ApplicationContextInitializer.class,最终调用方法是getSpringFactoriesInstances,注意第二个参数,传的是一个空的Class数组,则加载所有的配置的类,方便后续给定限定类型的时候无需再次加载,直接从cache中读取。
SpringFactoriesLoader.loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader):这个方法,其作用是使用给定的类加载器从“META-INF/spring.factories”加载给定类型的工厂实现的完全限定类名,即得到所有ApplicationContextInitializer接口实现类的完全限定类名,去重。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {return getSpringFactoriesInstances(type, new Class<?>[] {});}private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicates//得到所有ApplicationContextInitializer接口的实现类Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));//创建所有ApplicationContextInitializer接口实现类的实例List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);//根据order排序AnnotationAwareOrderComparator.sort(instances);return instances;
}
随后当做参数传递到createSpringFactoriesInstances方法中,这个方法主要作用就是根据传入的type类型,parameterTypes参数类型(空Class数组)以及得到的完全限定类名集合创建对象实例,其中getDeclaredConstructor方法作用是得到指定参数类型的构造方法,parameterTypes为空数组即的得到的就是默认构造方法。构造方法基本都是空的,所以无需关心创建Initializers实例的时候在构造方法中执行了什么操作。这些对象的initialize方法会在后面的run方法中被调用。
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,Set<String> names) {//new 一个跟检索出来的接口实现类相同size的ListList<T> instances = new ArrayList<>(names.size());for (String name : names) {try {//通过类加载器加载类Class<?> instanceClass = ClassUtils.forName(name, classLoader);//判断是否为ApplicationContextInitializer接口的实现类Assert.isAssignable(type, instanceClass);//得到指定参数类型的构造方法Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);//创建对象T instance = (T) BeanUtils.instantiateClass(constructor, args);//放到List中,返回instances.add(instance);}catch (Throwable ex) {throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);}}return instances;
}
spring.factories文件内容中Initializers如下。


1.3、设置Listener
这一步跟上面设置Initializers执行的操作是一样的。spring.factories文件内容中Listener如下。

整理一下Listener对应的Event
| 监听器 | 事件类型 |
|---|---|
| BackgroundPreinitializer | ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent、ApplicationFailedEvent、ApplicationContextInitializedEvent |
| ClearCachesApplicationListener | ContextRefreshedEvent |
| ParentContextCloserApplicationListener | ParentContextAvailableEvent |
| FileEncodingApplicationListener | ApplicationEnvironmentPreparedEvent |
| AnsiOutputApplicationListener | ApplicationEnvironmentPreparedEvent |
| ConfigFileApplicationListener | ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent |
| DelegatingApplicationListener | ApplicationEnvironmentPreparedEvent |
| ClasspathLoggingApplicationListener | ApplicationEnvironmentPreparedEvent、ApplicationFailedEvent |
| LoggingApplicationListener | ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、ContextClosedEvent、ApplicationFailedEvent |
| LiquibaseServiceLocatorApplicationListener | ApplicationStartingEvent |
1.4、推断main方法所在类
StackTraceElement数组包含了StackTrace(堆栈轨迹)的内容,通过遍历它可以得到当前方法以及其定义类、调用行数等信息。

private Class<?> deduceMainApplicationClass() {try {//获取StackTraceElement数组,也就是这个栈的信息。StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();for (StackTraceElement stackTraceElement : stackTrace) {if ("main".equals(stackTraceElement.getMethodName())) {//stackTraceElement.getClassName(),得到定义类,即main方法所在类return Class.forName(stackTraceElement.getClassName());}}}catch (ClassNotFoundException ex) {// Swallow and continue}return null;
}
SpringApplication对象的创建过程就完成了。
Springboot 启动还可以使用流式API SpringApplicationBuilder的方式启动:
@SpringBootApplication
public class RegisterApplication {public static void main(String[] args) {new SpringApplicationBuilder(RegisterApplication.class)// 设置当前应用类型.web(WebApplicationType.SERVLET)// 设置 banner 横幅打印方式、有关闭、日志、控制台.bannerMode(Banner.Mode.OFF)// 设置自定义的 banner.banner()// 追加自定义的 initializer 到集合中 .initializers()// 追加自定义的 listeners 到集合中.listeners().run(args);}
}
相关文章:
SpringBoot启动流程分析之创建SpringApplication对象(一)
SpringBoot启动流程分析之创建SpringApplication对象(一) 目录: 文章目录 SpringBoot启动流程分析之创建SpringApplication对象(一)1、SpringApplication的构造方法1.1、推断应用程序类型1.2、设置Initializers1.3、设置Listener1.4、推断main方法所在类 流程分析…...
SSH简介 特点以及作用
引言 SSH(Secure Shell)是一种用于安全远程访问和数据传输的网络协议。它提供了一种安全的机制,使得用户可以在不安全的网络中安全地进行远程登录、命令执行和文件传输。SSH通过加密技术和认证机制来保护数据的安全性,防止数据在…...
MQTT服务搭建及python使用示例
1、MQTT协议 1.1、MQTT介绍 MQTT(Message Queuing Telemetry Transport)是一种轻量级的、基于发布/订阅模式的通信协议,通常用于物联网设备之间的通讯。它具有低带宽、低功耗和开放性等特点,适合在网络带宽有限或者网络连接不稳定…...
Ubuntu如何设置中文输入法
概述 Ubuntu 是一个基于 Debian 构建的开源操作系统,拥有广泛的用户群体和强大的社区支持。是免费、开源的操作系统。被设计为一个适用于个人电脑、服务器和云平台的通用操作系统。Ubuntu的目标是提供一个稳定、易于使用和免费的操作系统,以促进人们在计…...
PostgreSQL的pg_dump和 pg_dumpall 异同点
PostgreSQL的pg_dump和 pg_dumpall 异同点 基础信息 OS版本:Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本:16.2 pg软件目录:/home/pg16/soft pg数据目录:/home/pg16/data 端口:5777pg_dump 和 pg_dum…...
【Ping】Windows 网络延迟测试 ping 、telnet、tcping 工具
ping 命令 属于网络层的ICMP协议,只能检查 IP 的连通性或网络连接速度, 无法检测IP的端口状态。 telnet telnet命令,属于应用层的协议,用于远程登录,也可用于检测IP的端口状态。但是功能有限,只能检测一时…...
DuDuTalk:4G桌面拾音设备在银行网点服务场景的应用价值
随着科技的飞速发展,银行业也在不断地寻求创新以提高服务质量和效率。在这个过程中,4G桌面拾音设备作为一种新型的智能设备,其在银行网点服务场景中的应用价值逐渐凸显出来。本文将从多个角度探讨4G桌面拾音设备在银行网点服务场景的应用价值…...
QT 设置窗口不透明度
在窗口作为子窗口时,setWindowOpacity设置窗口的不透明度可能会失效。 QGraphicsOpacityEffect *opacityEffect new QGraphicsOpacityEffect(this); opacityEffect->setOpacity(1.0); this->setGraphicsEffect(opacityEffect);// 创建属性动画对象ÿ…...
如何在Python中实现文本相似度比较?
在Python中实现文本相似度比较可以通过多种方法,每种方法都有其适用场景和优缺点。以下是一些常见的文本相似度比较方法: 1. 余弦相似度(Cosine Similarity) 余弦相似度是通过计算两个向量之间夹角的余弦值来确定它们之间的相似…...
韩顺平0基础学Java——第7天
p110-p154 控制结构(第四章) 多分支 if-elseif-else import java.util.Scanner; public class day7{public static void main(String[] args) {Scanner myscanner new Scanner(System.in);System.out.println("input your score?");int s…...
性能远超GPT-4!谷歌发布Med-Gemini医疗模型;李飞飞首次创业瞄准空间智能;疫苗巨头联合OpenAl助力AI医疗...
AI for Science 企业动态速览—— * 谷歌 Med-Gemini 医疗 AI 模型性能远超 GPT-4 * 斯坦福李飞飞首次创业瞄准「空间智能」 * 疫苗巨头 Moderna 与 OpenAl 达成合作 * 美国能源部推动 AI 在清洁能源领域的应用 * 美年健康荣获「2024福布斯中国人工智能创新场景应用企业TOP10」…...
中国科技大航海时代,“掘金”一带一路
文|白 鸽 编|王一粟 “这不就是90年代的内地吗?” 在深度考察完沙特市场后,华盛集团联合创始人兼CEO张霆对镜相工作室感慨道。 在张霆看来,沙特落后的基建(意味着大量创新空间)、刚刚开放…...
ffmpeg7.0 flv支持hdr
ffmpeg7.0 flv支持hdr 自从ffmpeg6.0应用enhance rtmp支持h265/av1的flv格式后,7.0迎来了flv的hdr能力。本文介绍ffmpeg7.0如何支持hdr in flv。 如果对enhance rtmp如何支持h265不了解,推荐详解Enhanced-RTMP支持H.265 1. enhance rtmp关于hdr 文档…...
【教程】极简Python接入免费语音识别API
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,请不吝给个[点赞、收藏、关注]哦~ 安装库: pip install SpeechRecognition 使用方法: import speech_recognition as srr sr.Recognizer() harvard sr…...
详解typora配置亚马逊云科技Amazon S3图床
欢迎免费试用亚马逊云科技产品:https://mic.anruicloud.com/url/1333 当前有很多不同的博客社区,不同的博客社区使用的编辑器也不尽相同,大概可以分为两种,一种是markdown格式,另外一种是富文本格式。例如华为云开发者…...
Python sqlite3库 实现 数据库基础及应用 输入地点,可输出该地点的爱国主义教育基地名称和批次的查询结果。
目录 【第11次课】实验十数据库基础及应用1-查询 要求: 提示: 运行结果: 【第11次课】实验十数据库基础及应用1-查询 声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 1.简答题 数据库文件Edu_Base.db&#…...
iOS-SSL固定证书
文章目录 1. SSL简介2. 证书锁定原理1.1 证书锁定1.2 公钥锁定1.3 客户端获取公钥1.4 客户端使用SSL锁定选择1.5 项目支持SSL证书锁定1.6 问题记录1. SSL简介 证书锁定(SSL/TLS Pinning)顾名思义,将服务器提供的SSL/TLS证书内置到移动端开发的APP客户端中,当客户端发起请求…...
docker 开启 tcp 端口
前言:查了很多网上资料 都说要修改daemons,json 完全不管用,而且还导致添加 {“host”:["tcp://0.0.0.0:2375","unix:///var/lib/docker.sock"]} 后,docker restart 失败,浪费了不少时间 !&am…...
zookeeper之分布式环境搭建
ZooKeeper的分布式环境搭建是一个涉及多个步骤的过程,主要包括准备工作、安装ZooKeeper、配置集群、启动服务以及验证集群状态。以下是搭建ZooKeeper分布式环境的基本步骤: 1. 准备工作 确保所有节点的系统时间同步。确保所有节点之间网络互通…...
java设计模式三
工厂模式是一种创建型设计模式,它提供了一个创建对象的接口,但允许子类决定实例化哪一个类。工厂模式有几种变体,包括简单工厂模式、工厂方法模式和抽象工厂模式。下面通过一个简化的案例和对Java标准库中使用工厂模式的源码分析来说明这一模…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
