SpringBoot是一个基于Spring框架的快速开发工具,可以帮助开发者快速搭建Web应用接口。而Tomcat则是一款常用的Web服务器,可以用来部署和运行Web应用。一般情况我们都喜欢使用SpringBoot默认自带的Tomcat来运行应用,方便开发部署,节省配置时间。
但是有些互联网大厂可能会限制使用Tomcat,主要出于安全性和性能等其他因素的考虑。那么,我们有没有其他的选择呢?当然有! 一种很好的选择是使用Undertow。
Undertow作为SpringBoot默认集成的三大容器之一(Tomcat、Jetty、Undertow)。首先它是Red Hat公司旗下的开源产品, 由Java语言开发,是一款灵活的高性能Web服务器;不仅支持阻塞IO还支持非阻塞IO,以及监听多端口等特性。由于Undertow通过java语言开发,即在java项目中使用可直接嵌入。而且,Undertow完全支持Servlet和Web Socket,在高并发情况下表现非常出色,总之,Undertow在性能和内存使用方面都优于Jetty和Tomcat。
实现步骤如下:
1).pom.xml
...
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
<mysql.version>8.0.21</mysql.version>
<hutool.version>5.8.18</hutool.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--排除spring-boot-starter-tomcat-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- 添加Undertow容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
<version>${spring-boot.version}</version>
</dependency>
<!--mysql的驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>${mysql.version}</version>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--糊涂工具类依赖-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
</dependencies>
2).application.yml
#yml格式配置文档范例
server:
#端口配置
port: 8080
## 支持的多端口监听,中间用,隔开,连续端口使用-进行链接
additional-ports: 8888,8889-8892
#上下文
servlet:
context-path: /undertowdemo
#数据源配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
#Springboot2.0 的hikari配置
hikari:
minimum-idle: 5
#空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 180000
#连接池最大连接数,默认是10
maximum-pool-size: 10
#此属性控制从池返回的连接的默认自动提交行为,默认值:true
auto-commit: true
#连接池名称
pool-name: MyHikariCP
#此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
max-lifetime: 1800000
#数据库连接超时时间,默认30秒,即30000
connection-timeout: 30000
connection-test-query: SELECT 1
jpa:
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
format_sql: true
enable_lazy_load_no_trans: true
hbm2ddl:
auto: update
3).添加监听多端口配置。
package com.simoniu.undertowdemo.config;
import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author: simoniu
* @date: 2022-12-16 18:14
* @description: 配置undertow监听多端口
*/
@Configuration
public class MultiplePortListerConfig {
/**
* 额外端口监听
*/
@Value("${server.additional-ports}")
private String additionalPorts;
@Bean
public ServletWebServerFactory undertowFactory() {
UndertowServletWebServerFactory undertowFactory = new UndertowServletWebServerFactory();
undertowFactory.addBuilderCustomizers(builder -> {
if (StrUtil.isBlank(additionalPorts)) {
return;
}
String[] ports = additionalPorts.split(",");
for (String port : ports) {
if (port.contains("-")){
String[] portArr = port.split("-");
int start = Integer.parseInt(StrUtil.trim(portArr[0]));
int end = Integer.parseInt(StrUtil.trim(portArr[1]));
for (int i = start; i<=end; i++){
builder.addHttpListener(i, "0.0.0.0");
}
}else {
builder.addHttpListener(Integer.parseInt(StrUtil.trim(port)), "0.0.0.0");
}
}
});
return undertowFactory;
}
}
4).启动项目,观察输出信息。
2023-10-11 22:30:19.637 INFO 8256 --- [ restartedMain] io.undertow : starting server: Undertow - 2.2.20.Final
2023-10-11 22:30:19.641 INFO 8256 --- [ restartedMain] org.xnio : XNIO version 3.8.7.Final
2023-10-11 22:30:19.644 INFO 8256 --- [ restartedMain] org.xnio.nio : XNIO NIO Implementation Version 3.8.7.Final
2023-10-11 22:30:19.668 INFO 8256 --- [ restartedMain] org.jboss.threads : JBoss Threads version 3.1.0.Final
2023-10-11 22:30:19.698 INFO 8256 --- [ restartedMain] o.s.b.w.e.undertow.UndertowWebServer : Undertow started on port(s) 8080 (http) 8888 (http) 8889 (http) 8890 (http) 8891 (http) 8892 (http) with context path '/undertowdemo'
2023-10-11 22:30:19.707 INFO 8256 --- [ restartedMain] c.s.u.UndertowdemoApplication : Started UndertowdemoApplication in 2.051 seconds (JVM running for 3.233)
5).测试监听多端口请求。

QPS测试结果对比:

通过测试发现,在高并发系统中,Tomcat相对来说比较弱。在相同的机器配置下,模拟相等的请求数,Undertow在性能和内存使用方面都是最优的。并且Undertow新版本默认使用持久连接,这将会进一步提高它的并发吞吐能力。所以,如果是高并发的业务系统,Undertow是最佳选择。