用了这么多年的 SpringBoot 你知道什么是 SpringBoot 的 Web 类型推断吗?

news2024/11/25 12:58:05

用了这么多年的 SpringBoot 那么你知道什么是 SpringBootweb 类型推断吗?

估计很多小伙伴都不知道,毕竟平时开发做项目的时候做的都是普通的 web 项目并不需要什么特别的了解,不过抱着学习的心态,阿粉今天带大家看一下什么是 SpringBootweb 类型推断。

SpringBoot 的 web 类型有哪些

既然是web 类型推断,那我们肯定要知道 SpringBoot 支持哪些类型,然后才能分析是怎样进行类型推断的。

根据官方的介绍 SpringBootweb 类型有三种,分别是,NONESERVLETREACTIVE,定义在枚举 WebApplicationType 中,这三种类型分别代表了三种含义:

  1. NONE:不是一个 web 应用,不需要启动内置的 web 服务器;
  2. SERVLET:基于 servletweb 应用,需要启动一个内置的 servlet 服务器;
  3. REACTIVE:一个 reactiveweb 应用,需要启动一个内置的 reactive 服务器;
public enum WebApplicationType {
 NONE,
 SERVLET,
 REACTIVE;
}

web 类型推断

上面提到了 SpringBoot 的三种 web 类型,接下来我们先通过代码验证一下,然后再分析一下 SpringBoot 是如何进行类型推断的。

首先我们通过在 https://start.spring.io/ 快速的构建三种类型的项目,三种类型的项目配置除了依赖不一样之外,其他都一样,如下所示

None web

none
none

下载后的项目文件 pom 中对应的依赖为

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter</artifactId>
</dependency>

Servlet web

servlet
servlet

下载后的项目文件 pom 中对应的依赖为

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Reactive web

reactive
reactive

下载后的项目文件 pom 中对应的依赖为

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

接下来我们依次启动三个项目看看有什么区别,

启动 None web

none-web
none-web

通过启动日志我们可以看到,在 None web 类型下,应用启动运行后就自动关闭了,并没有启动内置的 web 服务器,也没有监听任何端口。接下来我们看看其他两种类型 web 的启动日志都是怎么样的。

启动 Servlet web

servelt-web
servelt-web

通过启动日志我们可以看到这里启动了内置的 Tomcat Servlet 服务器,监听了 8080 端口,应用程序并不会像 None 类型一样,启动后就自动关闭。

启动 Reactive web

reactive-web
reactive-web

通过启动日志我们可以看到,这里启动了内置的 Netty 服务器,并监听在 8080 端口上(如果启动失败记得把上面 servlet web 关闭,不然端口会冲突)。

三种类型的服务我们都成功启动了,那么接下来的问题就是 SpringBoot 是如何判断出该使用哪种类型的呢?

这三个服务我们只有依赖不一样,很明显肯定和依赖有关系,接下来我们就来研究一下 SpringBoot 是如何实现的。

SpringBoot Web 类型推断原理

我们在 main 方法中点击 run 方法,

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

在构造函数中我们可以看到其中有这么一行 this.webApplicationType = WebApplicationType.deduceFromClasspath();根据属性名称我们可以推断,web 类型就是根据 WebApplicationType.deduceFromClasspath(); 这个静态方法来判断的。接下来我们看下这个方法的细节。

alt
alt

如上图所示,可以看到 SpringBoot 底层是通过 ClassUtils.isPresent() 方法来判断对应的 web 类型类是否存在来判断 web 类型的。

在前类路径下面如果当 org.springframework.web.reactive.DispatcherHandler 存在而且 org.springframework.web.servlet.DispatcherServletorg.glassfish.jersey.servlet.ServletContainer 都不存在的时候说明当前应用 web 类型为 Reactive

javax.servlet.Servletorg.springframework.web.context.ConfigurableWebApplicationContext 任何一个不存在的时候,就说明当前应用是 None 类型非 web 应用。否则当前应用就为 Servlet 类型。

而我们再看这个 ClassUtils.isPresent() 方法,可以发现底层是通过 className 在类路径上加载对应的类,如果存在则返回 true,如果不存在则返回 falseimage-20221224154733977

因此这也解释了为什么我们在 pom 文件中只要加入对应的依赖就可以直接得到相应的 web 类型了,因为当我们在 pom 中加入相应的依赖过后,类路径里面就存在了前面判断的对应的类,再通过 ClassUtils.isPresent() 就判断出来当前应用属于那种 web 类型了。

内置服务器是如何创建的

知道了 SpringBoot 是如何进行 web 类型推断的,那么接下来一个问题就是 SpringBoot 是如何根据 web 类型进行相应内置 web 服务器的启动的呢?这里我们以 Reactive web 为例进行调试追踪。

首先我们在 SpringApplicationrun 方法 createApplicationContext() 下一行打断点,可以发现创建成功的 context 类型为 AnnotationConfigReactiveWebServerApplicationContext 很明显在这一步的时候就已经根据类型推断得到了当前的应用 web 类型为 Reactive,并且根据 web 类型创建出了对应的 ApplicationContext

reactive-web
reactive-web

紧接着我们进入 org.springframework.boot.SpringApplication#refreshContext 方法,最后我们可以进入到 org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext#refresh 方法中,因为 AnnotationConfigReactiveWebServerApplicationContext 继承了 ReactiveWebServerApplicationContext

alt

继续通过引用关系,我们可以找到 org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext#onRefresh 方法,而在这个方法里面我们就会发现了如下代码,此处就会创建一个 webServer

alt

具体创建的方法在 WebServerManager 里面,跟着继续往下找我们可以找到 createHttpServer() 方法,在 createHttpServer() 方法中就创建了 HttpServer 并且绑定了默认的端口 8080。具体过程,如下几张接入所示,感兴趣的可以自行跟踪 debug,至此一个 Reactive 内置服务器就创建成功了,同样的 Servlet 服务器也是类似的。

alt alt alt alt

总结

Spring 的出现给 Java 程序员带来了春天,而 SpringBoot 框架的出现又极大的加速了程序员的开发效率,然而很多时候我们在使用她的便利的同时会缺少对于底层系统实现的把握,希望这篇文章弄帮助大家对 SpringBoot 产生更多的理解。

本文由 mdnice 多平台发布

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

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

相关文章

jQuery库冲突

文章目录jQuery库冲突原因jQuery.noConflict()如还想使用$可以这么做jQuery库冲突 原因 在某些情况下&#xff0c;可能有必要在同一个页面中使用多个JavaScript库。但是很多库都使用了“$”这个符号&#xff08;因为它简短方便&#xff09;&#xff0c;这时就需要用一种方式来…

Oracle中Null和无值的区别

以Leetcode第176题“第二高的薪水”为例。 首先说一下这道题最容易理解、最容易实现的解法&#xff0c;就是比最大值小的值里最大的值。 SELECT MAX(salary) AS SecondHighestSalary FROM Employee WHERE salary < (SELECT MAX(salary) FROM Employee)通过这道题目&#…

泛型------数据结构

泛型 问题:下面是一个简单的顺序表&#xff0c;我们在这里面实现的一个顺序表&#xff0c;是存放的数据类型只有int类型&#xff0c;这就会很不通用&#xff0c;如果我们想什么样的类型的数据都想要放进去,就要把这个数组的类型设置成Object类型 能不能啥样的类型都可以存放呢&…

ArcGIS中ArcMap栅格重采样操作与算法选择

本文介绍在ArcMap软件中&#xff0c;实现栅格图像重采样的具体操作&#xff0c;以及不同重采样方法的选择依据。 在文章Python中ArcPy实现栅格图像文件批量掩膜与批量重采样&#xff08;https://blog.csdn.net/zhebushibiaoshifu/article/details/124282764&#xff09;中&…

optimization问题的解决

目录 临界点critical point 基本介绍临界点两种情况的区分 g和H的举例介绍根据H区分Saddle Point和local minima 批次Batch batch大小的比较 时间的开销训练集和测试集的效果 训练集效果测试集效果 动量Momentum 一般的Gradient Descent带有动量的Gradient Descent 2021 -…

异步通信技术AJAX | 原理剖析、发送Ajax请求四步

目录 一&#xff1a;快速搞定AJAX&#xff08;第一篇&#xff09; 1、传统请求及缺点 2、AJAX请求原理剖析 3、AJAX概述 4、XMLHttpRequest对象 5、AJAX GET请求 6、AJAX GET请求提交数据 7、AJAX GET请求的缓存问题 8、AJAX POST请求及模拟表单提交数据 9、经典案例…

C语言基础--数组

文章目录一维数组一、一维数组的创建和初始化&#xff08;1&#xff09;一维数组的创建&#xff08;2&#xff09;一维数组的初始化1&#xff09;整形数组初始化2&#xff09;字符数组初始化3&#xff09;sizeof与strlen4&#xff09;总结二、一维数组的使用三、一维数组在内存…

基于C++实现(控制台)职工信息管理系统【100010060】

职工信息管理系统 一、实验内容 ​ 设计一个职工信息管理案例&#xff0c;实现不同类别职工的工资数据。职工的种类包括&#xff1a;正式职工和临时工。定义一个基本的职工类&#xff0c;基本信息包括&#xff1a;编号、姓名、性别、年龄、家庭住址、基本职务工资。派生出正式…

Quarkus实现第一个Hello World

Quarkus介绍 Quarkus 是一个为 Java 虚拟机&#xff08;JVM&#xff09;和原生编译而设计的全堆栈 Kubernetes 原生 Java 框架&#xff0c;用于专门针对容器优化 Java&#xff0c;并使其成为无服务器、云和 Kubernetes 环境的高效平台。 Quarkus 可与常用 Java 标准、框架和库…

php正则匹配反斜杠问题

php正则匹配反斜杠问题&#xff1a; 之前做了一道题&#xff0c;发现php中正则匹配反斜杠好像有点问题。 我们先看下面代码&#xff1a; <?php$cmd "\\";echo $cmd.PHP_EOL;if(preg_match("/\\\\|\\/",$cmd)) {echo "yes";} else {echo …

springdata-jpa-hibernate-03

springdata-jpa-hibernate-03 多表关联操作 首先加上这个lombok依赖,可以使代码更加简洁 一对一 account类 customerRepository接口 测试 一对多 message类 测试 多对一 在上面一对多的基础上加上这句代码就行 MessageRepository接口 测试&#xff1a; 多对多…

Mybatis-Plus快速入门

入门案例 MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具&#xff0c;旨在简化开发、提高效率开发方式基于MyBatis使用MyBatisPlus基于Spring使用MyBatisPlus基于SpringBoot使用MyBatisPlusSpringBoot整合MyBatis开发过程&#xff08;复习&#xff09;创建Spring…

DSP-Z变换

目录 Z变换的定义: Z变换的收敛域: 收敛域的定义: 收敛条件&#xff1a; Z变换收敛域的形状&#xff1a; 阿贝尔定理&#xff1a; 对于有限长序列的收敛域&#xff1a; Z变换的性质: 线性&#xff1a; 收敛域取交集&#xff1a; 时移&#xff1a; 指数相乘&#xf…

Java和Web前端哪个有发展前景?

Java和Web前端都是当今技术行业里的热门岗位&#xff0c;岗位招聘需求量大&#xff0c;人才竞争度高&#xff0c;同学们掌握这两个岗位里其中任何一个的相关主流技术&#xff0c;都可以找到一份不错的职位。下面请允许笔者做一个简要的分析阐述&#xff1a; 一、Web前端 Web前…

5 Redis

5.1 Redis 5.1.1 前言 前面使用到的mysql数据库会出现以下问题 由于用户量增大&#xff0c;请求数量也随之增大&#xff0c;数据压力过大 多台服务器之间数据不同步 多台服务器之间的锁&#xff0c;已经不存在互斥性了。 5.1.2 Redis 5.1.2.1 什么是Redis Redis&#x…

GO语言基础-05-循环和语句-select语句

文章目录1. 概述1.1 作用1.2 和switch比较1.3 执行过程2. 语法示例3. 完整示例1. 概述 1.1 作用 监听channel的数据流动 1.2 和switch比较 相同 开始的一个新的选择块&#xff0c;每个选择条件由case语句来描述。 不同 switch语句&#xff1a;可以选择任何使用相等比较的…

SpringCloud 协同开发方案

相比Springboot开发&#xff0c;SpringCloud开发要复杂的多&#xff0c;因为涉及服务的注册发现&#xff0c;多个微服务模块间的调用等。 最简单的解决方案是每个开发者都在本地启动一套完整的开发环境&#xff0c;包括网关、nacos等各个组成微服务的模块&#xff0c;如果系统…

Hive 学习Demo

背景介绍 陌陌作为聊天平台每天都会有大量用户在线&#xff0c;会出现大量的聊天数据&#xff0c;通过对聊天数据分析&#xff0c;可以更好的构建精确的用户画像&#xff0c;为用户提供更好的服务以及实现高ROI(投资回报率)的平台运营推广&#xff0c;给公司的发展决策提供精确…

智能网联汽车渗透率变化图显示预计

IDC 于 2020 年最新发布的《全球智能网 联汽车预测报告&#xff08;2020-2024&#xff09;》数据显示&#xff0c;尽管受新冠肺炎疫情冲击&#xff0c;2020 年全球智能网联汽车出货量预计较上一年下滑 10.6%&#xff0c;约为 4440 万辆&#xff0c;但到 2024 年全球智能网联汽车…

广播机制基础知识

广播机制 1.广播机制 1.1概述 1.1.1引入 1.广播的生活案例 记得以前读书的时候&#xff0c;每个班级都会有一个挂在墙上的大喇叭&#xff0c;用来广播一些通知&#xff0c;比如&#xff0c;开学要去搬书&#xff0c;广播&#xff1a; "每个班级找几个同学教务处拿书"…