Introduction #
In a Spring Boot-based web application, the spring-boot package contains a built-in web server, including tomcat
, jetty
, undertow
and netty
.
This article aims to clarify the principles and use of the built-in server in spring boot.
Spring Boot Server source code analysis #
First, let’s trace the code under the org.springframework.boot.web
package in the org.springframework.boot:spring-boot
package. The code can be found on Github spring-boot.
The directory structure under the package is as follows:
- embedded: mainly stores the built-in web server, including implementations such as WebServer and WebServerFactory, and also uses the corresponding server package
- reactive: a reactive-based spring boot application that depends on the
spring-boot-starter-webflux
package - servlet: a servlet-based spring boot application that depends on the
spring-boot-starter-web
package - server: server-related classes and interfaces common to servlet and reactive
Servlet and Reactive #
Spring Framework 5.0 provides two web frameworks: servlet
and reactive
. Their specific differences are as follows
-
servlet
was introduced in Spring Web and is based on the servlet API implementation, i.e. Spring MVC;reactive
was introduced through Spring Webflux and implements the reactive response of the Reactive Streams specification -
servlet
implements blocking I/Oreactive
implements Event-Loop, non-blocking I/O, i.e. asynchronous processing -
For the
servlet
framework, SpringBoot provides three built-in servers: Jetty, Tomcat and UndertowFor the
reactive
framework, SpringBoot provides four built-in servers: Jetty, Tomcat, Undertow and Netty
WebServer #
In this section, we will introduce the WebServer interface and implementation. The five methods provided by WebServer are as follows:
- start: start the service
- stop: stop the service
- getPort: provide the port number
- shutDownGracefully: gracefully shut down the service. It is called when attempting to end the service and handles some blocked requests
- destroy: destroy the service so that it cannot be started again. By default, the stop method is called
and then we look at the implementation of WebServer. The implementation mainly involves several servers built into spring-boot, specifically:
- JettyWebServer: a Jetty-based WebServer implementation that depends on
org.eclipse.jetty
- NettyWebServer: a Netty-based WebServer implementation that depends on
io.projectreactor
andio.netty
- TomcatWebServer: a WebServer implementation based on Tomcat, which depends on
org.apache.tomcat
- UndertowWebServer: a WebServer implementation based on Undertow, which depends on
io.undertow
Now that we know that the built-in WebServer in Spring Boot provides these implementations, which server is used by default when the service starts?
- With the servlet framework enabled, the default is TomcatWebServer, because
spring-boot-starter-web
depends onspring-boot-starter-tomcat
by default. - With the reactive framework enabled, the default is NettyWebServer, because
spring-boot-starter-webflux
depends onspring-boot-starter-reactor-netty
by default.
WebServerFactory #
Spring Boot provides the WebServerFactory factory interface class to encapsulate the creation of WebServer
WebServerFactory is also divided into two types: ServletWebServerFactory and ReactiveWebServerFactory. Both provide the getWebServer
method to create WebServer, but the specific differences are as follows
-
The ServletWebServerFactory provides the
getWebServer
method with the parameterorg.springframework.boot.web.servlet.ServletContextInitializer
, which is used to configure the Servlet 3.0+ interface.The ServletContextInitializer provides the
onStartup(ServletContext servletContext)
methodwhere
jakarta.servlet.ServletContext
is used to connect to the corresponding servlet container -
The parameter passed in to the
getWebServer
method provided by ReactiveWebServerFactory isorg.springframework.http.server.reactive.HttpHandler
**. **HttpHandler provides the
handle(ServerHttpRequest request, ServerHttpResponse response)
methodwhere
org.springframework.http.server.reactive.ServerHttpRequest
andorg.springframework.http.server.reactive.ServerHttpResponse
correspond to the request and response based on the reactive server
Server | Servlet stack | Reactive stack |
---|---|---|
Tomcat | TomcatServletWebServerFactory | TomcatReactiveWebServerFactory |
Jetty | JettyServletWebServerFactory | JettyReactiveWebServerFactory |
Undertow | UndertowServletWebServerFactory | UndertowReactiveWebServerFactory |
Reactor | N/A | NettyReactiveWebServerFactory |
The specific interfaces and implementation classes of WebServerFactory are shown in the figure below, and will not be described in detail here
Server bean management #
Above, we sorted out the WebServer and the factory class WebServerFactory used for management. Next, let’s analyze how SpringBoot manages Server Beans through the Factory.
The corresponding ServletWebServerApplicationContext
and ReactiveWebServerApplicationContext
have been created, and the onRefresh()
method has been implemented in these two classes. This method is used to initialize special beans in specific context subclasses. The specific context subclasses here include ServletWebServerApplicationContext, ReactiveWebServerApplicationContext and StaticWebApplicationContext, as follows:
- In
ServletWebServerApplicationContext
, theonRefresh()
method is used to obtain the ServletWebServerFactory Bean and create the WebServer - In
ReactiveWebServerApplicationContext
, theonRefresh()
method is used to obtain the ReactiveWebServerFactory Bean and create the WebServerManager, which in turn is used in the constructor of WebServer to create the WebServer - In the
StaticWebApplicationContext
, theonRefresh()
method is used to create the static theme of the ThemeSource
Brief introduction to built-in servers: Jetty/Netty/Tomcat/Undertow #
Here, I will not go into the implementation and differences between these four servers, but just briefly describe the implementation and differences.
Tomcat #
Tomcat is currently included in the Apache project. The official link is https://tomcat.apache.org/.
Tomcat is a mainstream Java web server, so it is very stable and mature. At the same time, the community is active and has abundant documentation and resources.
Tomcat can support the Http
, Http/2
, AJP
, and WebSocket
protocols, and supports Servlet 6.0
Jetty #
Jetty is a server provided by Eclipse. The official link is https://eclipse.dev/jetty/documentation.php.
Compared to Tomcat, it is more lightweight and has its own asynchronous support.
Jetty can support the Http
, Http/2
, Http/3
, AJP
, and WebSocket
protocols, and supports Servlet 6.0
Netty #
Netty is a time-driven asynchronous network framework that is widely used in high-performance network applications, especially server-side applications that handle a large number of concurrent connections. The official link is https://netty.io/index.html.
Netty supports almost all major protocols, including SSL/TLS
, ** HTTP
, ** HTTP/2
, HTTP/3
, WebSockets
, DNS
, ** SPDY
**, SMTP
, etc.
Undertow #
Undertow is a server provided by JBoos. The official address is https://undertow.io/
Undertow is characterized by its lightweight, high performance and low resource consumption, and supports embedded applications and microservices.
Undertow can support the Http
, Http/2
, WebSocket
protocols, and Servlet 4.0
Server comparison #
Here is a comparison of the server running status based on Tomcat/Jetty/Undertow, which mainly monitors memory usage, class loading, number of threads, requests per second and average processing time per request.
We can see that Jetty is more lightweight in terms of memory usage and class loading; Undertow is faster in terms of the number of requests processed and response time.
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 |
How to configure other servers in Spring-Boot #
In the last part, we will introduce how to use non-default servers in SpringBoot
Using the Jetty server #
Using Jetty in a Servlet framework:
<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>
Using Jetty with the Reactive Framework:
<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>
Using Undertow Server #
Use Undertow under a servlet framework:
<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>
Use Undertow with the Reactive Framework:
<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>
Using Tomcat with the Reactive Framework #
<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>
Support Netty under the Reactive framework and is compatible with Servlet #
If the original project is based on SpringMVC and you want to use Netty Server, you need to rely on SpringWebflux.
It is worth noting that SpringWebflux also supports traditional SpringMVC annotations such as @Controller and @RestController. The specific implementation class is AnnotationConfigReactiveWebServerApplicationContext
, which is a subclass of 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>
References #
Spring 5的Servlet和反应式技术栈解析_Java_Rossen Stoyanchev_InfoQ精选文章
Comparing Embedded Servlet Containers in Spring Boot | Baeldung
SpringBoot 2 performance — servlet stack vs WebFlux reactive stack