Skip to main content
  1. Articels/

Exploring the built-in Spring-Boot server

·1338 words·3 mins
Spring Framework Java language source code analysis
Weaxs
Author
Weaxs

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/O

    reactive implements Event-Loop, non-blocking I/O, i.e. asynchronous processing

  • For the servlet framework, SpringBoot provides three built-in servers: Jetty, Tomcat and Undertow

    For 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 and io.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 on spring-boot-starter-tomcat by default.
  • With the reactive framework enabled, the default is NettyWebServer, because spring-boot-starter-webflux depends on spring-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 parameter org.springframework.boot.web.servlet.ServletContextInitializer, which is used to configure the Servlet 3.0+ interface.

    The ServletContextInitializer provides the onStartup(ServletContext servletContext) method

    where jakarta.servlet.ServletContext is used to connect to the corresponding servlet container

  • The parameter passed in to the getWebServer method provided by ReactiveWebServerFactory is org.springframework.http.server.reactive.HttpHandler**. **

    HttpHandler provides the handle(ServerHttpRequest request, ServerHttpResponse response) method

    where org.springframework.http.server.reactive.ServerHttpRequest and org.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, the onRefresh() method is used to obtain the ServletWebServerFactory Bean and create the WebServer
  • In ReactiveWebServerApplicationContext, the onRefresh() 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, the onRefresh() 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
#

“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

Related

Why can Spring 'inject itself'?
·1142 words·6 mins
Java language Spring Framework source code analysis
Take a look at the Spring source code and PR records to find out which version and commit introduced the support for Self-Injection.