惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

豆逗子的小黑屋

GEMINI-CLI settings 参数详情 使用 sing-box Tun 模式实现 V2rayU 的透明代理 浅析 Claude Code 的执行与提示词 多模态模型是如何处理和理解图片的? 从配料表出发:便秘的猫应该怎么选主食 盘点开源的 DeepResearch 实现方案 浅谈 DeepSeek-R1 和 Kimi k1.5 论文中的思维链 + 强化学习 使用 TiDB Vector 构建 LightRAG 知识库 从论文到源码:详解 RAG 算法 云南之行——游在大理食在昆明 浅入浅出 Rerank 模型 一年同行:我的TiDB社区之旅 读书笔记《大语言模型》 TiDB Vector + Dify 快速构建 AI Agent 基于 LLM 推动游戏叙事 HTTP/2 和 CONTINUATION Flood 混合专家模型 (MoE) 笔记 报告分享: IMF第四次磋商报告 和 美联储研究笔记 使用 Coze 搭建 TiDB 助手 2023年总结 读书笔记《大规模语言模型:从理论到实践》 TiDB知识点梳理 (PCTA 笔记) 向量相似性检索方法 Java & Go 线程模式对比 Hugo + umami 博客统计面板 资产配置 101 搭建Go版本Kubernetes微服务示例 为什么Spring可以“自己注入自己” Go语言指针性能 从固定走向浮动 ——《时运变迁》读书笔记 Netty 源码分析及内存溢出思路 博客搭建简述 推荐 笔记 看得见的手——《置身事内》读书笔记 2022年初读书回顾 荐书:《走出唯一真理观》 nintendo switch 关于 邮箱
探究 Spring-Boot 内置Server
2023-07-30 · via 豆逗子的小黑屋

引言 #

基于Spring Boot的web应用中,在spring-boot包内包含了内置的 web server,具体包括 tomcatjettyundertownetty

本文旨在厘清spring boot中内置server的原理和使用。

首先我们跟踪一下 org.springframework.boot:spring-boot 包中 org.springframework.boot.web package下的代码,代码可以看 Github spring-boot

package下的目录结构如下:

  • embedded:主要是存放内置的web server,包含WebServer和WebServerFactory等实现,同时用到对应 server 的package
  • reactive:基于 reactive 的spring boot 应用,依赖spring-boot-starter-webflux
  • servlet:基于servlet的 spring boot 应用,依赖spring-boot-starter-web
  • server:servlet 和 reactive 中通用的 server 相关的类和接口

Servlet 和 Reactive #

Spring Framework 5.0 提供了两种web框架,分别是 servletreactive ,他们具体的不同如下

  • servlet 是Spring Web中引入,基于servlet API实现,即Spring MVC;

    reactive 是通过Spring Webflux引入,实现了Reactive Streams 规范的响应式

  • servlet 实现的是阻塞IO (blocking I/O)

    reactive 实现的是 Event-Loop,非阻塞IO(non-blocking I/O),即异步处理

  • 针对servlet 框架,SpringBoot提供了三种内置Server,分别是 JettyTomcatUndertow

    针对reactive 框架,SpringBoot提供了四种内置Server,分别是 JettyTomcatUndertowNetty

WebServer #

这部分我们介绍一下 WebServer 接口与实现,WebServer提供的5个方法如下:

  • start:启动服务
  • stop:停止服务
  • getPort:提供端口号
  • shutDownGracefully: 优雅地关闭服务,在尝试结束服务的时候调用,处理一些被阻止的请求
  • destroy:销毁服务使其无法再次启动,默认调用stop方法

然后我们来看看 WebServer 的实现,实现主要是spring-boot中内置的几个Server,具体有:

  • JettyWebServer:基于Jetty的WebServer实现,依赖于 org.eclipse.jetty
  • NettyWebServer:基于Netty的WebServer实现,依赖于 io.projectreactorio.netty
  • TomcatWebServer:基于Tomcat的WebServer实现,依赖于 org.apache.tomcat
  • UndertowWebServer:基于Undertow的WebServer实现,依赖于 io.undertow

目前我们知道了SpringBoot中内置的WebServer提供了这些实现,那么在服务启动时,默认使用的是哪个 Server 呢?

  • 启用 servlet 框架的情况下,默认使用的是 TomcatWebServer,因为spring-boot-starter-web 中默认依赖了spring-boot-starter-tomcat
  • 启用 reactive 框架的情况下,默认使用的是 NettyWebServer,因为spring-boot-starter-webflux 中默认依赖了 spring-boot-starter-reactor-netty

WebServerFactory #

SpringBoot中提供了WebServerFactory的工厂接口类,用来封装WebServer的创建

WebServerFactory也分为了两种即 ServletWebServerFactoryReactiveWebServerFactory,两者都提供了getWebServer 方法来创建WebServer,但具体有所不同

  • ServletWebServerFactory 提供的getWebServer 方法传入的参数是org.springframework.boot.web.servlet.ServletContextInitializer,用于配置Servlet 3.0+的接口。

    ServletContextInitializer中提供了onStartup(ServletContext servletContext) 方法

    其中jakarta.servlet.ServletContext用于连接对应的servlet容器

  • ReactiveWebServerFactory 提供的getWebServer 方法传入的参数是org.springframework.http.server.reactive.HttpHandler

    HttpHandler中提供了handle(ServerHttpRequest request, ServerHttpResponse response)方法

    其中 org.springframework.http.server.reactive.ServerHttpRequestorg.springframework.http.server.reactive.ServerHttpResponse 对应的则是基于reactive server的 request 和 response

Server Servlet stack Reactive stack
Tomcat TomcatServletWebServerFactory TomcatReactiveWebServerFactory
Jetty JettyServletWebServerFactory JettyReactiveWebServerFactory
Undertow UndertowServletWebServerFactory UndertowReactiveWebServerFactory
Reactor N/A NettyReactiveWebServerFactory

WebServerFactory具体的接口和实现类如下图,这里不再做详细说明

Server 的 Bean 管理 #

上面我们梳理了 WebServer 和 用于管理的工厂类 WebServerFactory,下面我们来剖析SpringBoot中是如何通过Factory管理Server Bean的。

创建了对应的ServletWebServerApplicationContextReactiveWebServerApplicationContext ,并在这两个类实现了 onRefresh() 方法,此方法用于在特定context子类中初始化特殊的bean,这里所指的特定context子类包含ServletWebServerApplicationContextReactiveWebServerApplicationContextStaticWebApplicationContext,具体如下:

  • ServletWebServerApplicationContext 中,onRefresh() 方法中获取 ServletWebServerFactory Bean 创建 WebServer
  • ReactiveWebServerApplicationContext 中,onRefresh() 方法中获取ReactiveWebServerFactory Bean,并创建WebServerManager,在 WebServerManager 的构造方法中创建了 WebServer
  • StaticWebApplicationContext中,onRefresh() 方法用于创建 ThemeSource 的静态主题

内置 Server 简述:Jetty/Netty/Tomcat/Undertow #

这里不会展开介绍这4种Server的实现和区别,只是稍微简述一下实现和不同点。

Tomcat #

Tomcat目前收录与 Apache 项目中,官方链接是https://tomcat.apache.org/

Tomcat是主流的Java Web Server,所以是十分稳定和成熟的,同时社区活跃文档和资源丰富。

Tomcat可以支持Http, Http/2 , AJP, WebSocket 协议,支持Servlet 6.0

Jetty #

Jetty是 Eclipse 提供的一款Server,官方链接是https://eclipse.dev/jetty/documentation.php

相比Tomcat它更加轻量级,有自己的异步支持。

Jetty可以支持Http, Http/2 ,Http/3, AJP, WebSocket 协议,支持Servlet 6.0

Netty #

Netty是一个基于时间驱动的异步网络框架,被广泛应用于高性能的网络应用程序,尤其是处理大量并发连接的服务端应用,官方链接是https://netty.io/index.html

Netty几乎支持了大部分的协议,有**SSL/TLS, ** HTTP, ** HTTP/2**, HTTP/3, WebSockets, DNS, ** SPDY **, SMTP

Undertow #

Undertow是 JBoos 提供的一款Server,官方地址是https://undertow.io/

Undertow的特点在于轻量级、高性能和地资源消耗,同时支持嵌入式应用程序和微服务。

Undertow可以支持Http, Http/2 , WebSocket 协议,支持Servlet 4.0

Server对比 #

这里贴一下基于Tomcat/Jetty/Undertow的Server运行情况,主要监控了 内存使用、类加载、线程数、每秒请求书 和 每个请求的平均处理时长。

我们可以得知,内存占用和类加载方面,Jetty更加轻量;处理请求数和响应时间方面,Undertow速度更快。

Metric Tomcat Jetty Undertow
jvm.memory.used (MB) 168 155 164
jvm.classes.loaded 9869 9784 9787
jvm.threads.live 25 17 19
Requests per second 1542 1627 1650
Average time per request (ms) 6.483 6.148 6.059

如何在 Spring-Boot 中配置其他 Server #

最后一部分我们介绍一下如何在 SpringBoot 中使用非默认的 Server

使用 Jetty Server #

在 Servlet 框架下使用 Jetty:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

在 Reactive 框架下使用 Jetty:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-reactor-netty</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

使用 Undertow Server #

在 Servlet 框架下使用 Undertow:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

在 Reactive 框架下使用 Undertow:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-reactor-netty</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

在 Reactive 框架下使用 Tomcat #

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-reactor-netty</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>

在 Reactive 框架下支持Netty, 且兼容 Servlet #

如果原有是基于SpringMVC的项目,想使用Netty Server,需要依赖SpringWebflux

值得注意的是 SpringWebflux 也是支持@Controller、@RestController 等传统SpringMVC注解的,具体实现的类是AnnotationConfigReactiveWebServerApplicationContext ,它是ReactiveWebServerApplicationContext 的子类。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
    </exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

参考 #

“How-to” Guides

ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean

Spring 5的Servlet和反应式技术栈解析_Java_Rossen Stoyanchev_InfoQ精选文章

Comparing Embedded Servlet Containers in Spring Boot | Baeldung

Tomcat vs. Jetty vs. Undertow: Comparison of Spring Boot Embedded Servlet Containers - Examples Java Code Geeks - 2023

SpringBoot 2 performance — servlet stack vs WebFlux reactive stack

Spring MVC Async vs Spring WebFlux | Baeldung