当前位置: 首页 > news >正文

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

监听器事件类型
BackgroundPreinitializerApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent、ApplicationFailedEvent、ApplicationContextInitializedEvent
ClearCachesApplicationListenerContextRefreshedEvent
ParentContextCloserApplicationListenerParentContextAvailableEvent
FileEncodingApplicationListenerApplicationEnvironmentPreparedEvent
AnsiOutputApplicationListenerApplicationEnvironmentPreparedEvent
ConfigFileApplicationListenerApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent
DelegatingApplicationListenerApplicationEnvironmentPreparedEvent
ClasspathLoggingApplicationListenerApplicationEnvironmentPreparedEvent、ApplicationFailedEvent
LoggingApplicationListenerApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent、ContextClosedEvent、ApplicationFailedEvent
LiquibaseServiceLocatorApplicationListenerApplicationStartingEvent
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对象(一) 目录&#xff1a; 文章目录 SpringBoot启动流程分析之创建SpringApplication对象(一)1、SpringApplication的构造方法1.1、推断应用程序类型1.2、设置Initializers1.3、设置Listener1.4、推断main方法所在类 流程分析…...

SSH简介 特点以及作用

引言 SSH&#xff08;Secure Shell&#xff09;是一种用于安全远程访问和数据传输的网络协议。它提供了一种安全的机制&#xff0c;使得用户可以在不安全的网络中安全地进行远程登录、命令执行和文件传输。SSH通过加密技术和认证机制来保护数据的安全性&#xff0c;防止数据在…...

MQTT服务搭建及python使用示例

1、MQTT协议 1.1、MQTT介绍 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的、基于发布/订阅模式的通信协议&#xff0c;通常用于物联网设备之间的通讯。它具有低带宽、低功耗和开放性等特点&#xff0c;适合在网络带宽有限或者网络连接不稳定…...

Ubuntu如何设置中文输入法

概述 Ubuntu 是一个基于 Debian 构建的开源操作系统&#xff0c;拥有广泛的用户群体和强大的社区支持。是免费、开源的操作系统。被设计为一个适用于个人电脑、服务器和云平台的通用操作系统。Ubuntu的目标是提供一个稳定、易于使用和免费的操作系统&#xff0c;以促进人们在计…...

PostgreSQL的pg_dump和 pg_dumpall 异同点

PostgreSQL的pg_dump和 pg_dumpall 异同点 基础信息 OS版本&#xff1a;Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本&#xff1a;16.2 pg软件目录&#xff1a;/home/pg16/soft pg数据目录&#xff1a;/home/pg16/data 端口&#xff1a;5777pg_dump 和 pg_dum…...

【Ping】Windows 网络延迟测试 ping 、telnet、tcping 工具

ping 命令 属于网络层的ICMP协议&#xff0c;只能检查 IP 的连通性或网络连接速度&#xff0c; 无法检测IP的端口状态。 telnet telnet命令&#xff0c;属于应用层的协议&#xff0c;用于远程登录&#xff0c;也可用于检测IP的端口状态。但是功能有限&#xff0c;只能检测一时…...

DuDuTalk:4G桌面拾音设备在银行网点服务场景的应用价值

随着科技的飞速发展&#xff0c;银行业也在不断地寻求创新以提高服务质量和效率。在这个过程中&#xff0c;4G桌面拾音设备作为一种新型的智能设备&#xff0c;其在银行网点服务场景中的应用价值逐渐凸显出来。本文将从多个角度探讨4G桌面拾音设备在银行网点服务场景的应用价值…...

QT 设置窗口不透明度

在窗口作为子窗口时&#xff0c;setWindowOpacity设置窗口的不透明度可能会失效。 QGraphicsOpacityEffect *opacityEffect new QGraphicsOpacityEffect(this); opacityEffect->setOpacity(1.0); this->setGraphicsEffect(opacityEffect);// 创建属性动画对象&#xff…...

如何在Python中实现文本相似度比较?

在Python中实现文本相似度比较可以通过多种方法&#xff0c;每种方法都有其适用场景和优缺点。以下是一些常见的文本相似度比较方法&#xff1a; 1. 余弦相似度&#xff08;Cosine Similarity&#xff09; 余弦相似度是通过计算两个向量之间夹角的余弦值来确定它们之间的相似…...

韩顺平0基础学Java——第7天

p110-p154 控制结构&#xff08;第四章&#xff09; 多分支 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」…...

中国科技大航海时代,“掘金”一带一路

文&#xff5c;白 鸽 编&#xff5c;王一粟 “这不就是90年代的内地吗&#xff1f;” 在深度考察完沙特市场后&#xff0c;华盛集团联合创始人兼CEO张霆对镜相工作室感慨道。 在张霆看来&#xff0c;沙特落后的基建&#xff08;意味着大量创新空间&#xff09;、刚刚开放…...

ffmpeg7.0 flv支持hdr

ffmpeg7.0 flv支持hdr 自从ffmpeg6.0应用enhance rtmp支持h265/av1的flv格式后&#xff0c;7.0迎来了flv的hdr能力。本文介绍ffmpeg7.0如何支持hdr in flv。 如果对enhance rtmp如何支持h265不了解&#xff0c;推荐详解Enhanced-RTMP支持H.265 1. enhance rtmp关于hdr 文档…...

【教程】极简Python接入免费语音识别API

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;请不吝给个[点赞、收藏、关注]哦~ 安装库&#xff1a; pip install SpeechRecognition 使用方法&#xff1a; import speech_recognition as srr sr.Recognizer() harvard sr…...

详解typora配置亚马逊云科技Amazon S3图床

欢迎免费试用亚马逊云科技产品&#xff1a;https://mic.anruicloud.com/url/1333 当前有很多不同的博客社区&#xff0c;不同的博客社区使用的编辑器也不尽相同&#xff0c;大概可以分为两种&#xff0c;一种是markdown格式&#xff0c;另外一种是富文本格式。例如华为云开发者…...

Python sqlite3库 实现 数据库基础及应用 输入地点,可输出该地点的爱国主义教育基地名称和批次的查询结果。

目录 【第11次课】实验十数据库基础及应用1-查询 要求: 提示: 运行结果&#xff1a; 【第11次课】实验十数据库基础及应用1-查询 声明&#xff1a;著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 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 端口

前言&#xff1a;查了很多网上资料 都说要修改daemons,json 完全不管用&#xff0c;而且还导致添加 {“host”:["tcp://0.0.0.0:2375","unix:///var/lib/docker.sock"]} 后&#xff0c;docker restart 失败&#xff0c;浪费了不少时间 &#xff01;&am…...

zookeeper之分布式环境搭建

ZooKeeper的分布式环境搭建是一个涉及多个步骤的过程&#xff0c;主要包括准备工作、安装ZooKeeper、配置集群、启动服务以及验证集群状态。以下是搭建ZooKeeper分布式环境的基本步骤&#xff1a; 1. 准备工作 确保所有节点的系统时间同步。确保所有节点之间网络互通&#xf…...

java设计模式三

工厂模式是一种创建型设计模式&#xff0c;它提供了一个创建对象的接口&#xff0c;但允许子类决定实例化哪一个类。工厂模式有几种变体&#xff0c;包括简单工厂模式、工厂方法模式和抽象工厂模式。下面通过一个简化的案例和对Java标准库中使用工厂模式的源码分析来说明这一模…...

从隔离到互联:工业现场中耐达讯自动化CC-Link IE转Modbus RTU实战指南

在工业自动化领域中&#xff0c;不同协议设备间的通信壁垒正成为智能制造的核心挑战之一。耐达讯自动化的CC-Link IE转Modbus RTU专用网关&#xff0c;通过硬件级协议转换技术&#xff0c;高效实现CC-Link IE高速以太网与Modbus RTU串口设备的无缝对接&#xff0c;帮助企业快速…...

LumiPixel Canvas Quest批量处理教程:使用Python脚本自动化生成人像图库

LumiPixel Canvas Quest批量处理教程&#xff1a;使用Python脚本自动化生成人像图库 1. 引言 最近遇到一个实际需求&#xff1a;需要为电商项目快速生成5000张不同风格的人像图片。手动一张张生成显然不现实&#xff0c;于是研究出了这套基于Python的自动化方案。用下来效果不…...

Kook Zimage真实幻想Turbo快速调试:找到属于你的幻想风格黄金参数组合

Kook Zimage真实幻想Turbo快速调试&#xff1a;找到属于你的幻想风格黄金参数组合 1. 认识Kook Zimage真实幻想Turbo Kook Zimage真实幻想Turbo是一款专为个人GPU设计的轻量化幻想风格图像生成系统。它基于Z-Image-Turbo极速文生图底座&#xff0c;通过独特的权重融合技术&am…...

2023年VSCode插件开发全指南:从零发布你的第一个扩展(TypeScript版)

2023年TypeScript生态下的VSCode插件开发实战 在当今开发者工具生态中&#xff0c;Visual Studio Code以其轻量化和高度可扩展性占据了绝对领先地位。根据2023年Stack Overflow开发者调查报告&#xff0c;VSCode以74.48%的使用率成为最受欢迎的代码编辑器。而插件系统正是其生态…...

GME-Qwen2-VL-2B助力AIGC内容创作:自动为图片生成创意文案与故事

GME-Qwen2-VL-2B助力AIGC内容创作&#xff1a;自动为图片生成创意文案与故事 你有没有过这样的经历&#xff1f;面对一张精心拍摄的照片&#xff0c;却怎么也憋不出几句像样的文案。或者&#xff0c;看着一张充满故事感的图片&#xff0c;脑海里思绪万千&#xff0c;落到笔尖却…...

SOONet实战教程:结合Whisper提取音频文本,构建音视频联合语义定位Pipeline

SOONet实战教程&#xff1a;结合Whisper提取音频文本&#xff0c;构建音视频联合语义定位Pipeline 1. 项目概述 今天给大家介绍一个特别实用的技术方案&#xff1a;如何用SOONet视频时序定位系统&#xff0c;结合Whisper语音识别&#xff0c;构建一个完整的音视频语义定位pip…...

知识点总结--day09(Mybatis及Mybatis-Plus)

目录 1、系统架构流程? 2结果集映射? 3mapper传参? 4、xml常用配置 5、缓存机制 6、分页插件 7、Mybatis-Plus常用API 末尾页 1、系统架构流程? 执行过程&#xff1a; mybatis配置 mybatis-config.xml&#xff0c;名称可变&#xff0c;此文件作为mybatis的全局配置…...

B站视频下载终极指南:DownKyi高效工具完整使用教程

B站视频下载终极指南&#xff1a;DownKyi高效工具完整使用教程 【免费下载链接】downkyi 哔哩下载姬downkyi&#xff0c;哔哩哔哩网站视频下载工具&#xff0c;支持批量下载&#xff0c;支持8K、HDR、杜比视界&#xff0c;提供工具箱&#xff08;音视频提取、去水印等&#xff…...

搞懂 SAP Fiori 前端服务器授权模型:从看得见应用,到真正拿到数据

在很多 SAP 项目里,权限问题最容易制造一种很迷惑的现象:用户明明已经拿到了角色,却还是打不开应用;或者磁贴已经能看见了,点进去却报错;再或者应用能启动,却一条业务数据都读不出来。要把这类问题讲清楚,关键不在于死记事务码,而在于真正理解 SAP Fiori 的授权是如何…...

FPGA Multiboot翻车实录:从XDC配置到ICAPE2,我的W25Q128分区血泪史与避坑指南

FPGA Multiboot实战&#xff1a;从配置陷阱到Flash分区优化的全流程解析 第一次在量产产品中实现FPGA远程更新功能时&#xff0c;我盯着实验室里突然变砖的开发板&#xff0c;后背渗出一层冷汗。原本以为按照官方文档配置就能万无一失&#xff0c;没想到Multiboot这个看似简单的…...