嵌入式Tomcat学习-第四天
写在前面
什么是嵌入式 Tomcat?
嵌入式 Tomcat 是将 Apache Tomcat 服务器作为库文件集成到 Java 应用程序中的技术方案。它允许开发者通过编程方式直接启动、配置和管理 Tomcat,无需依赖独立安装的 Tomcat 服务器,适用于构建轻量级、自包含的 Web 应用或微服务。
版本特性(11.0.3)
- Servlet/JSP 规范支持
支持 Servlet 6.0 和 JSP 4.0 规范(基于 Jakarta EE 10 平台)。 - 轻量级嵌入
通过tomcat-embed-core
等依赖包实现核心功能集成,无需完整 Tomcat 安装。 - Java 版本要求
最低要求 Java 17 及以上版本。 - 性能优化
改进的 HTTP/2 支持、连接器性能调优及内存管理优化。
核心优势
- 简化部署
应用与服务器一体化,直接打包为可执行 JAR 文件,适合云原生场景。 - 灵活配置
通过代码动态配置端口、上下文路径、SSL 等参数,无需server.xml
文件。 - 开发便捷
与 Spring Boot、Micronaut 等框架无缝集成,快速构建独立 Web 服务。 - 资源占用低
仅加载必要的组件,启动速度快,适合资源受限环境。
典型应用场景
- 微服务架构中的独立服务节点
- 快速原型开发或测试环境
- 命令行工具集成 Web 接口
- 需要定制化 Web 容器行为的场景
集成springmvc
什么是springmvc
SpringMVC 是 Spring Framework 的一部分,它实现了 Model-View-Controller (MVC) 设计模式,并用于构建灵活且松耦合的 web 应用程序。SpringMVC 提供了一种分离应用逻辑和用户界面的方法,这有助于开发者管理复杂的应用程序,并且使得应用程序更易于扩展和维护。
核心组件和功能
SpringMVC 的核心组件包括:
- DispatcherServlet:作为前端控制器,它负责将请求路由到不同的处理器。
- HandlerMapping:确定请求的目标处理器。
- Controller:处理请求并返回 ModelAndView 对象,其中包含模型数据和视图名称。
- ViewResolver:解析视图名称到具体的视图实现。
- Model:在控制器和视图之间传递数据。
- View:负责渲染模型数据,通常是 JSP 或 Thymeleaf 页面。
工作流程
SpringMVC 的工作流程涉及以下步骤:
- DispatcherServlet 接收到 HTTP 请求。
- HandlerMapping 确定请求的处理器。
- Controller 处理请求并返回 ModelAndView。
- ViewResolver 解析视图名称到具体视图。
- View 渲染模型数据并返回给客户端。
如何集成到tomcat中
移除上一篇文章中的struts相关内容
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lhstack.tomcat</groupId>
<artifactId>tomcat-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>11.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>11.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-websocket -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>11.0.3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>aliyun</id>
<name>阿里云</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<welcome-file-list>
<welcome-file>index</welcome-file>
</welcome-file-list>
</web-app>
保留如下图
修改main函数如下
package com.lhstack.tomcat;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.apache.tomcat.websocket.server.WsSci;
import java.util.Collections;
public class TomcatApplication {
public static void main(String[] args) throws Throwable {
Tomcat tomcat = new Tomcat();
//2025-02-15新增 新增webapp,指定路径
Context context = tomcat.addWebapp("", System.getProperty("user.dir") + "/webapp");
//2025-02-15 添加websocket支持和websocket连接监听器
context.addServletContainerInitializer(new WsSci(), Collections.singleton(WebSocketListener.class));
Connector connector = tomcat.getConnector();
connector.setPort(8080);
tomcat.start();
tomcat.getServer().await();
}
}
添加spring-webmvc依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lhstack.tomcat</groupId>
<artifactId>tomcat-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>11.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>11.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-websocket -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>11.0.3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>aliyun</id>
<name>阿里云</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
</project>
在web.xml添加dispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<welcome-file-list>
<welcome-file>index</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
在resource目录下面创建spring-mvc.xml
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="com.lhstack.tomcat.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
添加TestController
package com.lhstack.tomcat.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("test")
public class TestController {
@GetMapping
public Map<String,String> test(){
return Map.of("msg","hello world");
}
}
添加TestIndexController和修改index.jsp
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
Hello This Is Index Jsp
</body>
</html>
package com.lhstack.tomcat.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("jsp")
public class TestIndexController {
@GetMapping
public String index(){
return "WEB-INF/jsp/index.jsp";
}
}
启动项目并访问
集成log4j2
pom.xml增加相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lhstack.tomcat</groupId>
<artifactId>tomcat-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.24.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.24.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>11.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>11.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-websocket -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>11.0.3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>aliyun</id>
<name>阿里云</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
</project>
在resource目录添加log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="tomcat-demo">
<Properties>
<Property name="ConsolePattern">%d{yyyy-MM-dd HH:mm:ss} - ${sys:user.name} [%thread]|-%-5level %logger{100}-[ %msg ]%n%throwable</Property>
</Properties>
<Appenders>
<Console name="DefaultConsole" target="SYSTEM_OUT">
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${ConsolePattern}"/>
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="DefaultConsole"/>
</Root>
</Loggers>
</Configuration>
修改TestController,增加日志输出
package com.lhstack.tomcat.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("test")
public class TestController {
private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);
@GetMapping
public Map<String,String> test(){
LOGGER.info("test");
return Map.of("msg","hello world");
}
}
启动项目并测试
为log4j2增加异步支持
简介
异步特点
- 无锁队列设计:使用
Disruptor
库的环形缓冲区(RingBuffer),避免线程竞争,减少同步开销。 - 低内存分配:通过预分配内存和对象复用,减少垃圾回收压力。
- 非阻塞主线程:日志事件生成后立即返回,由独立线程处理写入,避免 I/O 阻塞主线程。
- 高并发优化:在大量并发请求下,异步模式显著减少日志记录对业务性能的影响。
- 独立线程池:异步日志使用专用后台线程处理写入,与应用线程隔离。
- 线程数控制:默认根据 CPU 核心数分配,避免过多线程竞争。
- 基于
Disruptor
的高性能无锁环形缓冲区,实现真正的非阻塞异步。 - 支持细粒度控制,可为不同 Logger 配置异步或同步模式。
潜在风险与注意事项
- 事件丢失风险:若系统崩溃时
RingBuffer
中未持久化的日志会丢失(可通过shutdownHook
缓解)。 - 延迟写入:异步模式下日志可能不会立即落盘,不适合对实时性要求极高的场景。
- 依赖 Disruptor:需引入
disruptor
依赖包以启用 AsyncLogger。
性能调优建议
- 增大 RingBuffer 容量:避免生产者(应用线程)与消费者(日志线程)速度不匹配导致的等待。
- 选择等待策略:根据场景平衡吞吐量与延迟(如
BlockingWaitStrategy
适合低延迟,SleepingWaitStrategy
适合高吞吐)
适用场景
- 高并发服务:如 Web 服务器、微服务等需要快速响应的场景。
- 性能敏感型应用:需减少日志记录对主业务线程的影响。
- 非关键日志:允许短暂延迟或少量日志丢失的场景(如调试日志)。
pom.xml增加相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lhstack.tomcat</groupId>
<artifactId>tomcat-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.lmax/disruptor -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>4.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.24.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.24.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>11.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>11.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-websocket -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>11.0.3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>aliyun</id>
<name>阿里云</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
</project>
在resources添加log4j2.system.properties
配置log4j2异步支持
log4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
log4j2.AsyncQueueFullPolicy=org.apache.logging.log4j.core.async.DiscardingAsyncQueueFullPolicy
log4j2.asyncLoggerRingBufferSize=1024
log4j2.asyncLoggerWaitStrategy=Yield
启动项目,debug查看
在AsyncLogger中debug查看是否进入
结尾
源码
今天介绍了如何在嵌入式tomcat中集成spring-webmvc,以及如何在项目中添加log4j2日志管理,以及如何集成异步日志达到高性能输入日志,大家可以通过这篇文章完成一个小小的demo,如一个简单的用户管理系统
嵌入式Tomcat学习-第四天
https://blog.lhstack.xyz/archives/tomcat-fourthday