SpringBoot嵌入式Servlet容器 相关学习笔记

news2025/7/16 2:24:47

  大家都知道SrpingBoot是内嵌Servlet容器的,并且默认是Tomcat,本文主要讲一下其中原理。
  首先,SpringBoot是支持其它容器的,除了Tomcat外,还有Undertow,Netty以及Jetty。并且这些容器经过封装,最终使用的时候,都是 一个WebServer。(但是一开始它们注册到IOC容器中时,并不是这种类型)
在这里插入图片描述
  接着开始讲原理,主要分两条线:一是web服务器的创建,二是web服务器的获取及使用。

1.web服务器的创建

  既然说服务器是嵌入式的,那必然是自动配置。SpringBoot自动配置类都是XXAutoConfiguration结尾,这里定位到ServletWebServerFactoryAutoConfiguration,这个类就是web服务器的自动配置类,但是服务器的创建并不直接在这个类完成,该类代码如下。

@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration

  观察@Import注解,服务器的具体配置其实是在ServletWebServerFactoryConfiguration这个类中完成的。进入该类,确实可以看到配置了各个服务器对应的bean:

在这里插入图片描述
在这里插入图片描述
  并且这几个web服务器组件,并不是无条件的注入到IOC容器中的,@ConditionalOnClass注解其实就是做限制的,如果连自身对应的jar包都没有,这个组件就不会被注入。从图片上可以看出,只有Tomcat是正常的,这也就解释了为什么SpringBoot内嵌的web服务器默认是tomcat。
  那么Tomcat所需的类为何会存在呢?这主要是因为SpringBoot在启动时发现当前是Web应用,web场景自动导入了tomcat。
  以上就是web服务器创建的基本流程,具体细节没有深入。

2.确定Web服务器

  刚刚说到这是web场景,而web场景对应的ioc容器,正是ServletWebServerApplicationContext
 这个类有一个属性就是WebServer,前面提到过,其实就是用来接受寻找到的web服务器。从该类的角度来说,其实就是创建WebServer,主要代码如下:

	private void createWebServer() {
	//当前是null
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
		//从这里正式开始创建WebServer
			StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
			//这是核心代码,寻找WebServerFactory,而WebServerFactory正是被刚刚标注@Bean注解的web三个服务器组件所间接实现。默认情况下,获取到的就是tomcat
			ServletWebServerFactory factory = getWebServerFactory();
			createWebServer.tag("factory", factory.getClass().toString());
			//将获取到的web容器赋给webServer
			this.webServer = factory.getWebServer(getSelfInitializer());
			createWebServer.end();
			getBeanFactory().registerSingleton("webServerGracefulShutdown",
					new WebServerGracefulShutdownLifecycle(this.webServer));
			getBeanFactory().registerSingleton("webServerStartStop",
					new WebServerStartStopLifecycle(this, this.webServer));
		}
		else if (servletContext != null) {
			try {
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
		initPropertySources();
	}
ServletWebServerFactory factory = getWebServerFactory();

  这是核心代码,可以看一下里面具体是如何实现的:
在这里插入图片描述
  里面逻辑还是比较简单的,其实就是查找容器中ServletWebServerFactory类型的组件的名字。这里不妨再看一下这是什么类型:
在这里插入图片描述
  通过图片,可以看的非常清楚,这是一个接口,而上文提到的几个服务器组件实现的它,那不就成了找生效的web服务器组件的name了嘛?
  通过前文可知,默认情况下,只有Tomcat成功注册,Debug一下:
在这里插入图片描述

return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);

  最后return根据name和type查到的明确的web服务器,返回的类型是ServletWebServerFactory。至此,已经获取到一个明确的webServer了。

this.webServer = factory.getWebServer(getSelfInitializer());

 因为这里的factory就是刚刚获取的TomcatServletWebServerFactory,所以getWebServer自然就是调用TomcatServletWebServerFactory中的方法:
在这里插入图片描述
 这不就是在配置具体的Tomcat嘛,这个方法过后,createWebServer()方法的主要内容已经完成。

3.拓展

3.1 如何切换服务器

 在前文中说了,为何是默认tomcat的原因,也解释了tomcat的类的来源,是在web场景下自动导入的。要切换成别的服务器,就要在web-start中排除tomcat相关依赖,并导入其他服务器的依赖,如下:
在这里插入图片描述

3.2 如何定制服务器(未完待续)

1. 直接在yaml文件中修改server为前缀的属性。 是因为在自动配置服务器组件的时候用到了ServerProperties这个类,而这个类中的属性又全来自properties。
在这里插入图片描述
2. 自定义ServletWebServerFactory。因为一开始在createWebServer()方法里是通过调用getWebServerFactory()得到服务器组件,具体是查找类型为ServletWebServerFactory.class的组件。前面说了ServletWebServerFactory是服务器组件间接实现的一个接口,所以可以通过修改父类/接口的功能,来对实现类/子类进行功能扩展。但是由于ServletWebServerFactory这个接口里方法实在是太少了,所以我们定义的是它的子接口ConfigurableServletWebServerFactory
在这里插入图片描述
3. 通过ServletWebServerFactoryCustomizer(Web服务器的定制化器)后置修改服务器工厂的属性。
在这里插入图片描述

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

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

相关文章

KAT: A Knowledge Augmented Transformer for Vision-and-Language

Paper name KAT: A Knowledge Augmented Transformer for Vision-and-Language Paper Reading Note URL: https://arxiv.org/pdf/2112.08614.pdf TL;DR 2022 NAACL 论文,提出了 Knowledge AugmentedTransformer (KAT),提出了一种同时利用显式和隐式…

记录第一次安装部署datadonphon遇到的坑和解决办法

故事开始之前,我在3台服务器里新建了一个abin用户,3台服务器都用abin和root账号做了免密登录。故事开始了......按照官网文档一顿操作猛如虎到了配置集群了。那就配置呗,点它。仔细阅读了提示,嗯,明白它的意思了。来吧…

Python进阶-----高阶函数->filter() 函数

目录 前言: filter() 函数介绍 filter() 函数使用示例 1.与循环对比 2.与lambda函数综合使用 3.使用None过滤False 4.过滤字典相关数据 前言: 家人们,当你们获取了一个序列的时候,想要把一些内容去掉,保留一部分…

《JavaEE》进程和线程的区别和联系

👑作者主页:Java冰激凌 📖专栏链接:JavaEE 目录 进程是什么? 线程是什么? 进程和线程之间的联系~ ps1:假设我们当前的大兴国际机场有一条登机口可以登入飞机 ps2:我们为…

运动员最佳匹配问题(详解)

一、问题描述 羽毛球队有男女运动员各n人。给定2个nn矩阵P和Q。 P[i][j]是男运动员i的女运动员j配对组成混合双打的男运动员竞赛优势;Q[i][j]是女运动员i和男运动员j配对的女运动员竞赛优势。由于技术配合和心理状态等各种因素影响,P[i][j]不一定等于Q[…

LearnOpenGL-光照-6.多光源

本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正 我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject 文章目录前言例子代码没有聚光灯效果有聚光灯效果前言 此节目的 综合2.5投光物,在此节实现一个场…

超越语言界限,ChatGPT进化之路——Visual ChatGPT

❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…

操作系统复习

熟练掌握操作系统的定义,操作系统的特征,操作系统的功能熟练掌握多道程序设计的概念,单道程序设计和多道程序设计的区别,多道程序设计的优点熟悉操作系统接口的主要功能,系统调用的基本概念、类型、实现。操作系统接口…

【Mysql】库的操作

一、sql分类 1.DDL(Data Defination Language)数据定义语言 定义数据时候使用的sql语言 creat:建表、drop:删表、alter:改变 2.DML(Data Manipulation Language)数据操纵语言 对数据进行操作的sql语言 insert:插入、delet…

【打造家庭服务器系列03】Frp 实现内网穿透

一、概述 为什么要搞frp,因为我们的服务器处于家里面的网络,是没有公网IP的,所以直接通过ssh连接服务器,此时就需要一个中转来实现转发。 二、服务端配置 - Frp Server 以腾讯云为例,阿里云也一样。Frp 官方文档 -…

chatPDF | 别再自己读文献了!让chatGPT来帮你读吧!~

1写在前面 自从chatGPT开放API以后,相关基于此的app也是层出不穷。🤪 ChatGPT API是基于OpenAI的自然语言处理模型的API。🧐 基于这个API,开发人员可以通过程序调用和使用ChatGPT模型来解决各种文本相关的任务。😉 其实…

Ubuntu软件包管理之apt与apt-get的区别

目录apt和apt-get发展史apt和apt-get命令对比常用命令举例更新存储库索引升级已安装的包列出所有可用安装包关键字搜索安装包安装软件卸载软件查看安装包信息清理没用的依赖包清理下载的缓存包清理残余的配置文件查看安装包的依赖参考apt和apt-get发展史 Debian 使用一套名为 …

STM32—LCD1602

LCD1602(Liquid Crystal Display)是一种工业字符型液晶,能够同时显示 1602 即 32 字符(16列两行) 第 1 脚: VSS 为电源地 第 2 脚: VDD 接 5V 正电源 第 3 脚: VL 为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最…

C语言实现快速排序(hoare法、挖坑法、前后指针法与非递归实现)——不看后悔系列

目录 1. hoare法 方法与步骤 代码实现 2. 挖坑法 方法与步骤 代码实现 3. 前后指针法 方法与步骤 代码实现 4. 快速排序的缺点与优化 1.快速排序的缺点 2.快速排序的优化 ① 三数取中法选 key 代码实现 ② 小区间优化 代码实现 5. 快速排序的非递归实现 附录…

数据结构与算法基础(王卓)(16):KMP算法详解(代码实现)

实现代码的过程中 具体细节、问题: (1):关于写Get_next函数的标题: 现象: PPT上写的是: void get_next(SString T, int &next[]) 然而并不能运行,而当我们去掉了引用符号&…

记录踩过的坑-Git

Git命令克隆很慢原命令:git clone -b r1.13.0 https://github.com/tensorflow/models.git现在替换为:git clone -b r1.13.0 https://github.com.cnpmjs.org/tensorflow/models.git也就是把原 URL 中的 github.com 替换为 github.com.cnpmjs.org&#xff…

设计模式第9式:迭代器模式

前言 我们有很多种方法可以把对象集中到一个集合中,比如列表、堆栈、散列表中。每种集合都有自己的特点和使用时机,但都有一个共同的需求:用户想要遍历这些对象。同时我们并不想用户看到集合的实现,本文将讲解如何让用户遍历对象…

JVM垃圾回收器详解

垃圾收集器没有在规范中进行过多的规定,可以由不同的厂商、不同版本的JVM来实现。由于JDK的版本处于高速迭代过程中,因此Java发展至今已经衍生了众多的GC版本。从不同角度分析垃圾收集器,可以将GC分为不同的类型。1、垃圾回收器分类1.1、按线…

国际安全领域顶会NDSS 2023录稿整理 (下)

隐私计算研习社 NDSS是网络和系统安全领域的四大顶级国际学术会议(BIG4)之一,第三十届会议于2023年2月27日到3月3日,在美国圣迭戈举办。本文将接着整理剩余论文,并对论文进行分类,感兴趣的小伙伴可以访问论…

【Linux】信号+再谈进程地址空间

目录 一、Linux中的信号 1、Linux中的信号 2、进程对信号的处理 3、信号的释义 二、信号的捕捉 1、信号的捕捉signal() 2、信号的捕捉sigaction() 三、信号如何产生? 1、kill()用户调用kill向操作系统发送信号 通过命令行参数模仿写一个kill命令 2、rais…