引言
基于 Spring Boot 的 web 应用中,在 spring-boot 包内包含了内置的 web server,具体包括 tomcat、jetty、undertow 和 netty。
本文旨在厘清 spring boot 中内置 server 的原理和使用。
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 框架,分别是 servlet 和 reactive ,他们具体的不同如下
-
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,分别是 Jetty、Tomcat 和 Undertow针对
reactive框架,SpringBoot 提供了四种内置 Server,分别是 Jetty、Tomcat、Undertow 和 Netty
WebServer
这部分我们介绍一下 WebServer 接口与实现,WebServer 提供的 5 个方法如下:
-
start:启动服务
-
stop:停止服务
-
getPort:提供端口号
-
shutDownGracefully: 优雅地关闭服务,在尝试结束服务的时候调用,处理一些被阻止的请求
-
destroy:销毁服务使其无法再次启动,默认调用 stop 方法
然后我们来看看 WebServer 的实现,实现主要是 spring-boot 中内置的几个 Server,具体有:
-
JettyWebServer:基于 Jetty 的 WebServer 实现,依赖于
org.eclipse.jetty -
NettyWebServer:基于 Netty 的 WebServer 实现,依赖于
io.projectreactor和io.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 也分为了两种即 ServletWebServerFactory 和 ReactiveWebServerFactory,两者都提供了 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.ServerHttpRequest和org.springframework.http.server.reactive.ServerHttpResponse对应的则是基于 reactive server 的 request 和 response
WebServerFactory 具体的接口和实现类如下图,这里不再做详细说明
Server 的 Bean 管理
上面我们梳理了 WebServer 和 用于管理的工厂类 WebServerFactory,下面我们来剖析 SpringBoot 中是如何通过 Factory 管理 Server Bean 的。
创建了对应的 ServletWebServerApplicationContext 和 ReactiveWebServerApplicationContext ,并在这两个类实现了 onRefresh() 方法,此方法用于在特定 context 子类中初始化特殊的 bean,这里所指的特定 context 子类包含 ServletWebServerApplicationContext、ReactiveWebServerApplicationContext 和 StaticWebApplicationContext,具体如下:
-
在
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,官方地址是
Undertow 的特点在于轻量级、高性能和地资源消耗,同时支持嵌入式应用程序和微服务。
Undertow 可以支持 Http, Http/2 , WebSocket 协议,支持 Servlet 4.0
Server 对比
这里贴一下基于 Tomcat/Jetty/Undertow 的 Server 运行情况,主要监控了 内存使用、类加载、线程数、每秒请求书 和 每个请求的平均处理时长。
我们可以得知,内存占用和类加载方面,Jetty 更加轻量;处理请求数和响应时间方面,Undertow 速度更快。
如何在 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>