Tomcat 嵌入式开发详解
从 Tomcat 7 开始,官方提供了嵌入式支持,允许通过 Java 代码直接创建和启动 Tomcat 服务器,无需手动配置 server.xml 等文件。这种方式广泛应用于开发工具(如 IDEA 内置服务器)、集成测试及轻量级应用部署。本文将详细介绍 Tomcat 嵌入式开发的核心用法和实践案例。
嵌入式 Tomcat 核心组件
嵌入式 Tomcat 的核心类是 org.apache.catalina.startup.Tomcat,它封装了 Tomcat 服务器的创建、配置和启动流程。主要涉及以下组件:
Tomcat 类:服务器入口,负责初始化和启动整个 Tomcat 实例。
Context 类:代表一个 Web 应用上下文,对应传统的 <Context> 配置。
Host 类:虚拟主机,用于管理多个 Context。
Connector 类:连接器,配置端口、协议等网络参数。
入门示例:快速启动嵌入式 Tomcat
依赖配置
使用 Maven 引入嵌入式 Tomcat 依赖(以 Tomcat 9 为例):
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>9.0.80</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>9.0.80</version> </dependency>
|
映射简单 Servlet
通过代码创建并启动 Tomcat,直接映射一个 Servlet 处理请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import org.apache.catalina.LifecycleException; import org.apache.catalina.startup.Tomcat; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;
public class EmbeddedTomcatDemo { public static void main(String[] args) throws LifecycleException { Tomcat tomcat = new Tomcat(); tomcat.setPort(8080); org.apache.catalina.Context context = tomcat.addContext("/test", null); String servletName = "helloServlet"; Tomcat.addServlet(context, servletName, new HttpServlet() { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello, Embedded Tomcat!"); } }); context.addServletMappingDecoded("/hello", servletName); tomcat.init(); tomcat.start(); System.out.println("Tomcat 启动成功,访问 http://localhost:8080/test/hello"); tomcat.getServer().await(); } }
|
运行结果:
访问 http://localhost:8080/test/hello,页面显示 Hello, Embedded Tomcat!。
核心 API 解析
Tomcat 类核心方法
| 方法 |
功能描述 |
setPort(int port) |
设置默认连接器端口(默认 8080)。 |
addContext(String contextPath, String docBase) |
创建 Web 应用上下文,contextPath 为访问路径,docBase 为应用目录(null 表示内存中运行)。 |
addWebapp(String contextPath, String docBase) |
部署本地 Web 应用(支持 WAR 包或目录)。 |
init() |
初始化 Tomcat 服务器(加载配置)。 |
start() |
启动 Tomcat 服务器。 |
getServer().await() |
阻塞当前线程,防止服务器退出。 |
Context 类核心操作
Context 代表一个 Web 应用,主要用于配置 Servlet、过滤器、初始化参数等:
1 2 3 4 5 6 7
| Tomcat.addServlet(context, "myServlet", new MyServlet()); context.addServletMappingDecoded("/my/*", "myServlet");
ServletHolder holder = new ServletHolder(new MyServlet()); context.addServletMappingDecoded("/my/*", holder);
|
1 2
| context.setInitParameter("appName", "EmbeddedApp");
|
1
| context.setSessionTimeout(30);
|
部署本地 Web 应用
除了动态注册 Servlet,嵌入式 Tomcat 还支持部署本地已有的 Web 应用(如传统的 WAR 包或目录结构)。
示例:部署本地 Web 应用目录
假设本地有一个标准 Web 应用,目录结构如下:
1 2 3 4 5 6
| mywebapp/ ├── WEB-INF/ │ ├── web.xml │ ├── classes/ │ └── lib/ └── index.jsp
|
部署代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class DeployWebappDemo { public static void main(String[] args) throws LifecycleException, ServletException { Tomcat tomcat = new Tomcat(); tomcat.setPort(8080); String webappDir = "path/to/mywebapp"; tomcat.addWebapp("/app", webappDir); tomcat.init(); tomcat.start(); System.out.println("Web 应用部署成功,访问 http://localhost:8080/app"); tomcat.getServer().await(); } }
|
说明:
addWebapp 方法会自动解析 WEB-INF/web.xml 中的配置(Servlet、过滤器等)。
- 支持直接部署 WAR 包(
docBase 设为 WAR 文件路径即可)。
自定义连接器配置
默认情况下,嵌入式 Tomcat 使用 8080 端口和 HTTP/1.1 协议。可通过自定义 Connector 调整网络参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class CustomConnectorDemo { public static void main(String[] args) throws LifecycleException { Tomcat tomcat = new Tomcat(); org.apache.catalina.connector.Connector connector = new org.apache.catalina.connector.Connector( "org.apache.coyote.http11.Http11NioProtocol" ); connector.setPort(8081); connector.setRedirectPort(8443); tomcat.setConnector(connector); org.apache.catalina.Context context = tomcat.addContext("/", null); Tomcat.addServlet(context, "hello", new HttpServlet() { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.getWriter().write("Custom Connector: 8081"); } }); context.addServletMappingDecoded("/*", "hello"); tomcat.init(); tomcat.start(); System.out.println("访问 http://localhost:8081"); tomcat.getServer().await(); } }
|
实践场景与优势
1. 典型应用场景
- 开发工具集成:IDE(如 IntelliJ IDEA、Eclipse)内置嵌入式 Tomcat,简化开发调试。
- 自动化测试:在单元测试中启动嵌入式 Tomcat,模拟真实环境测试 Web 接口。
- 轻量级部署:无需安装 Tomcat,直接通过 JAR 包启动应用(如 Spring Boot 内嵌 Tomcat)。
- 微服务场景:每个服务独立启动嵌入式 Tomcat,避免端口冲突和配置繁琐。
2. 优势
- 零配置:无需手动编写
server.xml、web.xml,通过代码动态配置。
- 轻量级:仅引入必要依赖,减少资源占用。
- 灵活性高:可根据业务需求动态调整服务器参数(如端口、线程池)。
- 易于集成:方便嵌入到其他应用中,作为内置服务器使用。
注意事项
- 依赖冲突:嵌入式 Tomcat 可能与项目中其他 Servlet 容器依赖(如 Jetty)冲突,需排除冗余依赖。
- JSP 支持:若需解析 JSP,需额外引入
tomcat-embed-jasper 依赖。
- 资源路径:部署本地 Web 应用时,
docBase 需使用绝对路径或正确的相对路径(避免因工作目录变化导致找不到资源)。
- 端口占用:启动前检查端口是否被占用,可通过
setPort(0) 让系统自动分配空闲端口。
v1.3.10