Tomcat实战指南:从安装部署、war包配置到JVM调优与HTTPS双向认证

发布时间:2026/9/16 5:34:24

Tomcat实战指南:从安装部署、war包配置到JVM调优与HTTPS双向认证 还在调Tomcat启动闪退、部署war包404、改配置改到怀疑人生……这些坑我基本都踩过一轮了。这篇文章把Tomcat从安装选型、IDE配置、war包部署到server.xml核心参数、内存调优、常见故障排查再到稍微进阶一点的双向HTTPS认证实验一次讲清楚。里面所有步骤都是我实际验证过的可以直接照着做。1. Tomcat到底是干嘛的为什么Java Web离不开它1.1 从一个Servlet请求说起很多刚接触Java Web的同学把Tomcat当成一个简单的启动就能跑的工具但完全不理解它做了什么。我用一个最直白的场景来解释你写了一个Servlet里面有个doGet方法你想让用户在浏览器输入http://localhost:8080/hello就能看到响应。问题是你写的Servlet是纯Java类它自己不监听端口不解析HTTP协议也不知道怎么把响应写回浏览器。谁来做这些事就是Tomcat。Tomcat本质上是一个Servlet容器 HTTP服务器。它启动后监听8080端口默认把收到的HTTP请求解析成HttpServletRequest对象然后根据请求路径找到对应的Servlet调用它的service方法再把HttpServletResponse里的内容封装成HTTP响应写回给浏览器。整个过程里解析协议管理生命周期线程分配这些脏活累活全是Tomcat干的你只需要关心业务逻辑。这也是为什么Spring Boot出现后很多人觉得没有Tomcat也能跑Web应用——其实不是没Tomcat而是Spring Boot把Tomcat内嵌进了工程你启动main方法时它自动帮你把内嵌Tomcat拉起来了。这个区别很关键后面我会专门讲。1.2 Tomcat源码与目录结构的对应关系拿一个标准的Tomcat 9解压包来看目录大概是这样的目录作用bin存放启动与关闭脚本如startup.sh、shutdown.sh、catalina.shconf全局配置文件重点是server.xml、web.xml、context.xmllibTomcat依赖的jar包比如servlet-api.jarlogs运行日志默认有catalina.out、localhost_access_log等temp临时文件目录webapps放置web应用的位置war包或解压后的目录都放这里workJSP翻译成Servlet后的Java源码与class文件存放位置work目录很多人不知道但对排查JSP问题极有用。JSP第一次被访问时Tomcat会把它翻译成一个Servlet的Java文件然后编译成class。翻译出来的Java文件就放在work/Catalina/localhost/你的应用名/org/apache/jsp/下面。如果你怀疑JSP里写的Java代码有语法问题或者想确认Tomcat到底把JSP编译成什么样直接去这个目录看源码就行。1.3 选对版本比会配置更重要Tomcat版本和Java版本是强绑定的版本不匹配会直接启动失败或者报UnsupportedClassVersionError。我在实际工作中见过太多人拿Tomcat 10去跑Java 8的老项目结果Servlet类都找不到因为Tomcat 10开始用的是Jakarta EE命名空间javax.servlet变成了jakarta.servlet旧代码直接编译不过。版本选型上我的建议是如果你在学传统的Servlet/JSPJava 8 Tomcat 9是最稳的组合网上资料多坑基本都被踩平了。如果你用Java 11及以上的新特性考虑Tomcat 10.1但注意项目依赖的Servlet版本也要跟上。Spring Boot项目别手动装Tomcat直接用内嵌的版本由Spring Boot父依赖统一管理。别用Tomcat 10以下的版本配Java 17JSP编译时会出现奇怪的反射报错。下载的话认准Apache官网的Tomcat发布页面Windows选zip包Linux选tar.gz包不要下源码包Source Code Distribution去自己编译那是自己给自己找事。2. Tomcat安装与配置从Windows到Linux一次说清2.1 环境准备先确认JDK装好没有Tomcat本身是用Java写的运行它必须有JDK或JRE。装好之后先验证java -version如果提示找不到命令说明JDK没装好或者环境变量JAVA_HOME没配。Windows用户在系统环境变量里新建JAVA_HOME指向JDK的实际安装目录比如C:\Program Files\Java\jdk1.8.0_202然后再在Path里加上%JAVA_HOME%\bin。Linux用户用export设置或者写入/etc/profile格式类似。安装Tomcat其实没有安装这个动作下载对应系统版本的压缩包解压到一个没有空格的路径Windows尤其是路径有空格会坑死你就算安装完成了。比如Windows就解压到D:\apache-tomcat-9.0.85Linux就解压到/opt/tomcat。2.2 Windows下启动与停止的正确姿势在bin目录下能看到startup.bat和shutdown.bat。直接双击startup.bat会弹出一个命令行窗口如果窗口一闪而过大概率是JAVA_HOME没配好。遇到这种情况不要慌不双击startup.bat改成在命令行里进到bin目录手动执行catalina.bat run这样Tomcat会以前台模式运行所有启动日志直接打在当前窗口报什么错一目了然。启动成功的话控制台会输出类似这样的内容信息 [main] org.apache.catalina.startup.Catalina.start Server startup in [1234] milliseconds然后浏览器访问http://localhost:8080能看到默认首页。如果8080端口被占用启动日志里会报java.net.BindException: Address already in use这时要么换端口要么找出占用进程。停止服务用shutdown.bat即可。注意shutdown是依靠8005端口发送SHUTDOWN命令实现的后面我把server.xml的时候会说。2.3 Linux服务器上部署war包的标准流程Linux上最常干的一件事情就是把打好的war包扔到Tomcat里跑起来。完整流程是# 1. 解压Tomcat tar -zxvf apache-tomcat-9.0.85.tar.gz mv apache-tomcat-9.0.85 /usr/local/tomcat # 2. 把war包放到webapps目录 cp myproject.war /usr/local/tomcat/webapps/ # 3. 后台启动 /usr/local/tomcat/bin/startup.sh # 4. 看日志 tail -f /usr/local/tomcat/logs/catalina.out这里有一个很容易犯的错Tomcat默认在conf/server.xml里配置了autoDeploytrue也就是说你把war包扔进webapps目录它会自动解压并部署。但是如果你之前已经用shutdown.sh停掉了Tomcat再复制war包然后又没有清空work目录启动后访问新版本页面发现还是老内容——这不是没部署是旧版本的class文件还留在work目录里。规范做法是先停Tomcat删掉webapps下旧的解压目录和war包删掉work目录下的对应缓存再放新war包最后启动。排查进程用的是ps -ef | grep tomcat或者更精确一些用ps -ef | grep java看Java进程的启动参数。如果启动后访问不了优先看logs/catalina.out日志比任何猜测都靠谱。2.4 验证一轮手动的完整部署我建议每个初学者都手动做一遍从下载到部署war包的全过程。可以自己打一个最简单的war在任意目录建一个文件夹叫demo里面建WEB-INF/web.xml和index.jsp。index.jsp里随便写一行h1Hello Tomcat/h1。用jar -cvf demo.war *打包在demo目录内执行或者直接用IDEA的Build Artifact。把demo.war复制到webapps启动Tomcat。访问http://localhost:8080/demo/。这一步做完你对整个Tomcat的工作原理就会有一个直观的感知原来war包放到webapps下Tomcat会自动解压、编译JSP、启动应用。之后再去调配置、弄双向认证就有了底层基础。3. IDEA、Eclipse集成Tomcat以及war包部署方式的选择3.1 IDEA 2025版本配置Tomcat详细步骤IDEA配置Tomcat分配置Tomcat服务器和配置部署方式两步。先说配置服务器打开IDEA进入File - Settings - Build, Execution, Deployment - Application Servers点加号选Tomcat Server然后在Tomcat Home中选择你的Tomcat解压目录。IDEA会自动识别版本号填好Tomcat Base Directory一般和Home一致点OK保存。这一步如果识别不到版本基本是JDK没配对IDEA会在下方提示按提示把Project SDK设成对应版本的JDK。然后是部署Web项目。这里要区分情况传统Web项目没有用Maven骨架创建的标准模板或者老式Java EE项目打开Project Structure - Artifacts点加号添加Web Application Exploded设置好Output directoryIDEA会把你项目里的JSP、class、resources打成一个可运行结构。Maven项目直接用插件方式运行或者同样在Artifacts里配置war exploded。接着在Run - Edit Configurations里点加号选Tomcat Server - Local。切到Deployment标签页点加号选Artifact把刚才配置的war exploded选中。Application context可以设置成/demo之类的路径这个决定了访问时的根路径。最后启动浏览器自动打开http://localhost:8080/你的context。3.2 为什么推荐Deployment用Exploded而不是war包IDEA里部署时你会看到两个选择demo:war和demo:war exploded很多人不理解差别。demo:war是完整war包IDEA会先构建war再复制到Tomcat的webapps目录Tomcat再解压。每次改代码都要重新打包开发效率低。demo:war exploded是直接把编译后的目录结构交给Tomcat相当于IDEA帮你维护了一个已经解压好的应用目录。配合IDEA的Update resources和热部署按钮改个JSP、改个静态资源点击更新就能立即生效不用重启服务。我的开发习惯是日常开发一律用exploded模式发布到测试机或生产环境才用完整war包。前者是为了开发效率后者是为了环境一致。3.3 Eclipse配置Tomcat和IDEA有什么不同Eclipse用的是Server视图模式流程上略有差异。先在Window - Preferences - Server - Runtime Environments里Add一个Tomcat版本指定安装目录然后到Servers视图里新建一个Server实例。Eclipse有个比较坑的地方默认Server Locations是Use workspace metadata也就是它不会用你解压出来的Tomcat的webapps目录而是在workspace里建一份副本。有时候你在tomcat/webapps下放了外部war包发现没生效原因就在这。建议在Servers视图双击Server打开配置面板把Server Locations改成Use Tomcat installation并且把Deploy Path设置成webapps。这样行为和手动部署就一致了。另一个常见坑是Eclipse部署后访问http://localhost:8080/项目名出现404但IDEA里同样的项目没问题。多半是Eclipse的Context Path和artifact名字不一致在Server配置的Modules标签页里检查一下Path列改成实际想要的访问路径。3.4 部署后去哪儿看JSP编译出的Java类不管用哪种IDE部署成功之后你都可以去Tomcat的work目录看JSP底部。比如应用名是demo访问过一次index.jsp后去work/Catalina/localhost/demo/org/apache/jsp/目录会看到index_jsp.java和index_jsp.class两个文件。打开index_jsp.java里面是Tomcat生成的Servlet代码。你能清楚地看到JSP里的HTML内容被写进了out.write()方法里JSP里的表达式% ... %被写进了out.print()调用里你声明的局部变量变成了_jspService方法内的局部变量。这个文件在看JSP编译报错时尤其有用Tomcat日志里报的行号经常是编译后Java文件的行号而不是JSP的行号对着这个文件更快定位。4. server.xml核心配置与JVM调优参数实践4.1 从一段实际配置认识server.xml的骨架Tomcat全局配置的核心在conf/server.xml。打开一个默认的配置文件你会看到这样的结构Server port8005 shutdownSHUTDOWN Service nameCatalina Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 / Engine nameCatalina defaultHostlocalhost Host namelocalhost appBasewebapps unpackWARstrue autoDeploytrue /Host /Engine /Service /Server理解这个结构有个生活化类比Server是整栋楼Service是楼里的营业模块Connector是接待前台Engine是业务调度室Host是楼层Context是房间。请求从Connector进来经过Engine分配到Host下的某个Context也就是具体某个Web应用处理。几个关键属性逐一说port8005 shutdownSHUTDOWN这是Tomcat用来接收关闭命令的端口。执行shutdown.sh就是往这个端口发一个SHUTDOWN字符串。这个端口只监听本机不需要暴露到外网最好别改除非和别的程序冲突。port8080HTTP访问端口要开外网访问的话记得在防火墙放行。redirectPort8443当请求要求HTTPS但当前Connector是HTTP时Tomcat会把请求重定向到8443端口。这个属性在配置HTTPS后特别容易踩坑后面实验部分会具体说。protocolHTTP/1.1默认的NIO连接器。不要改成HTTP/1.0性能差别很大。connectionTimeout20000接收请求后等待参数的毫秒数默认20秒。4.2 Host、Context与虚拟主机配置Host标签的namelocalhost表示域名。你想用自定义域名访问比如www.mysite.com就在这里加一个Host节点或者把localhost改成你的域名。appBasewebapps表示应用的根目录是webapps。Context有两种配置方式一种是在Host标签内显式写Context path/demo docBaseD:/projects/demo reloadabletrue /另一种是在conf/Catalina/localhost/下放一个demo.xml文件文件名就是path。第二种方式在生产环境更推荐改配置不用动主文件。docBase可以指向Tomcat外部目录这个很实用。比如你不想把项目文件放到Tomcat的webapps里就能用docBase/data/apps/myapp来指定。reloadabletrue开启后class或配置文件发生变化会自动重新加载开发方便生产环境建议改成false省去不必要的类加载开销。4.3 JVM内存参数怎么调才不OOM很多人问Tomcat启动报java.lang.OutOfMemoryError: PermGen space或者Java heap space怎么办这其实不是Tomcat的问题是JVM的内存参数设置问题。Tomcat启动脚本里默认的JVM堆内存很小并发稍高就爆了。修改方法是编辑bin/catalina.shLinux/Mac或bin/catalina.batWindows在文件开头加上JAVA_OPTS-Xms512m -Xmx1024m -XX:MaxPermSize256m参数含义参数作用-Xms512mJVM初始堆内存大小-Xmx1024mJVM最大堆内存大小生产环境至少2g以上-XX:MaxPermSize老版本的永久代内存大小Java 8之后改成-XX:MaxMetaspaceSize-XX:UseG1GC用G1垃圾回收器Java 8更新版后建议加上JDK1.8之后不用设置PermSizeMetaspace默认是无限的但保险起见可以设置-XX:MaxMetaspaceSize256m防止极端情况内存泄漏。有一个误区必须指出堆内存不是越大越好-Xmx设置太大反而会导致GC停顿时间变长。一般的原则是堆最大值不超过物理内存的50%比如8G内存的服务器设置-Xmx4g左右再配合-Xmn设置新生代大小。改完之后重启Tomcat效果立竿见影。怎么看当前JVM实际参数用jps查看进程号再用jinfo -flags 进程号就能看到全部启动参数。4.4 并发连接参数到底怎么配默认情况下Tomcat的HTTP连接器是单线程的吗不是。NIO连接器内部有一个线程池默认maxThreads是200。这意味着同一个时刻最多有200个请求在并行处理超过的请求会在acceptCount队列里排队。acceptCount默认100排队的连接超过这个数会被拒绝。生产环境可以根据机器配置适当调大Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 maxThreads400 maxConnections1000 acceptCount200 minSpareThreads50 /maxThreads不是无脑调大。每个线程占用一定的内存和CPU资源线程数过多上下文切换反而拖慢性能。我的建议是CPU核心数乘以25左右作为初始值跑压力测试观察响应时间和CPU占用再微调。minSpareThreads意思是启动时预创建多少空闲线程设成50左右可以加速请求响应。5. 高频报错排查从启动失败到404的完整方案5.1 启动一闪而过怎么定位Windows下双击startup.bat窗口一闪就没是最常见的问题之一。原因可能有三个JAVA_HOME未配置或路径错误。8080端口被其他程序占用。bin目录下的catalina脚本权限或编码问题。定位方法很简单在命令行里执行catalina.bat runTomcat会以前台模式启动原来一闪而过的错误信息会完全显示出来。如果是JAVA_HOME配置错误它会在开头直接报找不到java.exe如果是端口占用会报java.net.BindException。看到具体报错再对症下药。有个冷门坑有的人从云盘下载的所谓Tomcat集成环境bin目录里有些bat文件被Windows Defender或者安全软件拦截执行到一半被kill表现就是窗口闪一下就没了。解决方法解压路径不要放在桌面或下载目录放在一个干净的目录比如D:\dev\然后确认脚本没被杀毒软件隔离。5.2 启动成功但访问404启动日志显示Server startup in xxx milliseconds但浏览器访问http://localhost:8080出现404或者是访问自己部署的项目时404。分情况排查如果是访问根路径404说明ROOT应用没生效。检查webapps下有没有ROOT文件夹如果误删了Tomcat能启动但首页确实不存在。如果是访问http://localhost:8080/demo/404先看webapps下有没有对应的demo目录或demo.war。war包在部署时会自动解压如果没解压说明解压失败去logs里看catalina.out的详细报错。如果确认war包已解压、目录都存在那要看logs/localhost_access_log.*.txt。这个文件记录了所有的HTTP访问日志状态码404会记录在最后几位。同时看localhost.*.log日志那是具体某个应用启动时的日志。还有一个隐蔽问题你在IDEA里设置了Application context为/此时访问路径应该是http://localhost:8080/而不是/demo。很多人在这里绕晕。5.3 端口占用与8005奇怪的关闭行为报错java.net.BindException: Address already in use: JVM_Bind null:8080说明8080端口被其他进程占用了。Windows下用netstat -ano | findstr :8080看到占用端口的PID之后打开任务管理器找到对应进程结束它。如果这个进程是之前没关干净的Tomcat别直接结束进程尝试执行一次shutdown.bat让它走正常关闭流程。有时候Tomcat进程还活着执行shutdown.bat却提示没有这个进程检查一下conf/server.xml里8005端口是否被改过shutdownSHUTDOWN的值是否被改过。我遇到过有人把shutdown属性改成了SHUTDOWN123结果用默认的shutdown.bat永远关不掉服务。5.4 war包部署失败的日志解读war包部署常见的报错有这几种解压失败日志里出现Exception processing ... war多半是war包损坏用压缩软件重新打包或者用jar -xvf检查完整性。启动时ClassNotFoundException或NoClassDefFoundError说明war包WEB-INF/lib下缺少某个jar或者jar版本冲突。检查一下你的项目依赖里的两个jar是否同时引入了同一个类的不同版本。应用启动成功但访问时一直转圈日志里出现大量org.apache.catalina.core.StandardWrapperValve的报错这类一般是应用自身的异常需要看localhost.log里完整的堆栈。还有一种我现在都还会踩的坑war包里的WEB-INF/web.xml写的版本号是3.1但Tomcat版本是10.0Servlet 5.0编译器会报web-app_3_1.xsd not found或类似错误。这不是致命错误但会引入奇怪的运行行为。最好的做法是web.xml的版本和容器版本保持一致。5.5 高并发场景下的超时问题实际部署到服务器后偶尔会碰上请求响应特别慢或偶尔超时的情况。这时候先看connectionTimeout有没有被误调大。我见过有人为了防止超时把connectionTimeout调到60万毫秒的结果就是有个连接卡住不放线程池很快被占满所有请求看起来都变慢了。正确的思路是分层排查网络层用curl -w查看各自耗时确定是建立连接慢还是响应慢。应用层看catalina.out有没有长时间GC停顿用jstat -gcutil 进程号查看GC使用率。容器层检查线程池是否被打满。jstack导出线程快照看看大量线程阻塞在哪里。遇到偶发超时不要猜拿线程快照和GC数据说话大部分问题都能当场定位。6. 实验把Tomcat配成双向HTTPS客户端实现mTLS认证6.1 这个实验解决什么问题搜索热词里有tomcat做为客户端,请求服务端,实现mtls双向认证配置这个属于有点进阶的内容但实际项目里确实会用到。它解决的是这样一个问题你的Java后端服务A要调用另一个服务B的HTTPS接口而且B要求客户端出示证书mTLS双向认证。你不想写独立的Java客户端代码而是想让服务A本身跑在Tomcat里能带着证书去请求B。换句话说这里的关键不是Tomcat自己作为被访问的服务器而是要回答如何在Tomcat环境里配置一个可以发起HTTPS请求、并携带客户端证书的HTTP客户端。下面用Java原生API实现不需要引入额外框架如果你项目里是Spring的RestTemplate或者HttpClient原理一样只是封装了底层。6.2 用keytool生成服务端和客户端证书mTLS需要两对密钥服务端一对客户端一对。先建目录存证书我放在/tmp/mtls实际项目请放在受保护的目录。执行# 服务端密钥库 keytool -genkeypair -alias serverkey -keyalg RSA -keysize 2048 \ -validity 365 -keystore server.keystore -storepass server123 \ -dname CNlocalhost, OUDev, OExample, LCity, STState, CCN # 客户端密钥库 keytool -genkeypair -alias clientkey -keyalg RSA -keysize 2048 \ -validity 365 -keystore client.keystore -storepass client123 \ -dname CNclient, OUDev, OExample, LCity, STState, CCN # 导出证书并互相导入信任库 keytool -export -alias serverkey -keystore server.keystore -storepass server123 \ -file server.cer keytool -export -alias clientkey -keystore client.keystore -storepass client123 \ -file client.cer keytool -import -alias servercert -file server.cer -keystore client.truststore \ -storepass client123 -noprompt keytool -import -alias clientcert -file client.cer -keystore server.truststore \ -storepass server123 -noprompt-dname里的CNlocalhost很重要如果服务端地址是IP或域名这里要和访问地址匹配否则握手时报证书主机名不匹配。6.3 Tomcat服务端启用HTTPS并开启客户端证书校验如果Tomcat是服务端需要在server.xml里新增或修改一个Connector。默认配置里8080那个Connector有redirectPort8443这个8443就是给HTTPS预留的。增加一个专门的双向认证ConnectorConnector port8443 protocolorg.apache.coyote.http11.Http11NioProtocol SSLEnabledtrue schemehttps securetrue clientAuthtrue sslProtocolTLS keystoreFileconf/server.keystore keystorePassserver123 truststoreFileconf/server.truststore truststorePassserver123 /注意几个属性的作用clientAuthtrue表示强制要求客户端出示证书改成want表示请求客户端证书但客户端不提供也能建立连接。keystoreFile是服务端私钥所在的密钥库用于向客户端证明自己身份。truststoreFile是信任库注意它和keystoreFile必须分开因为它存放的是被信任的客户端证书。配置完成后重启Tomcat浏览器访问https://localhost:8443会出现客户端证书选择框如果你已把客户端证书导入浏览器这就是双向认证正在工作的表现。6.4 纯Java客户端发起mTLS请求现在写一个最直观的Java客户端代码里嵌入了加载密钥库的逻辑import javax.net.ssl.*; import java.io.*; import java.net.URL; import java.security.KeyStore; public class MtlsClient { public static void main(String[] args) throws Exception { // 加载客户端密钥库 KeyStore clientKs KeyStore.getInstance(JKS); try (InputStream ksIn new FileInputStream(client.keystore)) { clientKs.load(ksIn, client123.toCharArray()); } KeyManagerFactory kmf KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm()); kmf.init(clientKs, client123.toCharArray()); // 加载信任库 KeyStore trustKs KeyStore.getInstance(JKS); try (InputStream tsIn new FileInputStream(client.truststore)) { trustKs.load(tsIn, client123.toCharArray()); } TrustManagerFactory tmf TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustKs); SSLContext ctx SSLContext.getInstance(TLS); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory()); URL url new URL(https://localhost:8443/); HttpsURLConnection conn (HttpsURLConnection) url.openConnection(); conn.setRequestMethod(GET); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); int code conn.getResponseCode(); System.out.println(HTTP状态码: code); try (BufferedReader br new BufferedReader( new InputStreamReader(conn.getInputStream()))) { String line; while ((line br.readLine()) ! null) { System.out.println(line); } } } }这一段代码的核心逻辑是KeyManagerFactory负责提供客户端证书TrustManagerFactory负责校验服务端证书。两个角色不能混。实际项目里如果服务端只要求单向HTTPS那么客户端只需要配置TrustManager不需要KeyManager。如果连接报SSLHandshakeException99%是证书链不完整或信任库没有正确导入对方证书。用keytool -list -keystore查看信任库内容确认证书已经导入。6.5 在Tomcat应用里封装一个可复用的HTTPS客户端工具前面是独立Java程序实际是要在Tomcat里跑的Web应用内调用别人的接口。可以把上面逻辑封装成一个工具类每次请求时复用SSLContext避免每次new一个否则高并发下性能很差。public class MtlsHttpUtil { private static volatile SSLContext sslContext; public static SSLContext getSslContext() throws Exception { if (sslContext null) { synchronized (MtlsHttpUtil.class) { if (sslContext null) { // 加载客户端密钥库和信任库逻辑同前 sslContext buildSslContext(); } } } return sslContext; } }然后在Servlet或业务代码中用HttpsURLConnection或者把sslContext塞给HttpClient使用。重点提醒生产环境别把keystore密码硬编码在代码里从配置文件读取且配置文件本身要有访问控制。7. 从传统Tomcat到内嵌Tomcat再到其他Web容器7.1 Spring Boot里的Tomcat到底做了什么Spring Boot项目里没有单独的Tomcat安装目录但运行时你依然会在日志里看到Tomcat的启动信息这是因为spring-boot-starter-web默认引入了spring-boot-starter-tomcat应用启动时在内存中创建了一个内嵌Tomcat实例。这种模式下你不需要管理server.xml、不用去webapps下放war包只需要在application.yml里配置server: port: 8080 servlet: context-path: /demo tomcat: max-threads: 200 accept-count: 100Spring Boot还允许你替换掉Tomcat改成Undertow或Jetty。只需要在Maven里排除Tomcatdependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId exclusions exclusion groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-tomcat/artifactId /exclusion /exclusions /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-undertow/artifactId /dependency至于引入具体容器后怎么配线程池和SSL各自有独立的配置前缀。这里不细说但思路一样先搞懂Web容器通用概念再迁移到具体产品上会快得多。7.2 老项目迁移到其他Web容器时要注意什么一个传统Web项目如果想从一个Web容器迁移到另一个Web容器比如想把Tomcat换成其他主流中间件需要注意三点。第一Servlet API版本。项目里web.xml的version和依赖的javax.servlet版本决定了容器的最低要求容器低于这个版本会启动报错。第二JSP标签库依赖。项目里引了哪些JSTL实现jar不同容器自带的库可能冲突迁移后出现NoClassDefFoundError就先清理WEB-INF/lib里已有的servlet-api和jsp-api相关的jar这些容器自带不要打包进去。第三部署结构差异。有的容器解压war的路径、自动部署机制和日志目录不太一样命令行参数和JMX端口基本不通用。7.3 容器选型的个人建议传统Servlet/JSP教学和老系统维护Tomcat 9是最省心的新项目如果不想被容器管理拖累Spring Boot内嵌Tomcat最顺手想极致压缩内存、提高吞吐可以考虑Undertow它的内存占用比Tomcat低不少至于国内一些金融或政务项目要求用国产中间件替换这类一般就是运维指定的开发侧改动不大核心思路是理解它们只是Web容器的不同实现部署方式类似。8. 再补几个我自己常用的排查和调优小技巧最后分享几个翻来覆去用得上的小技巧不算系统知识但关键时刻能救你一把。catalina.out文件越来越大磁盘被塞满这在长线运行的服务器上几乎是必然遇到的事。别等爆了再处理提前配置logrotate或者自己写定时任务按大小切割。实在不行重启时把catalina.out清空也行 /usr/local/tomcat/logs/catalina.out这不影响运行只是清空文件内容。排查进程用的是ps -ef | grep tomcat但有时候进程存在端口也监听正常却怎么都访问不了。别忘了看防火墙。Linux下:firewall-cmd --list-ports firewall-cmd --add-port8080/tcp --permanent firewall-cmd --reload很多部署问题不是Tomcat的问题是防火墙把端口挡了。还有一个跟路径有关的坑生产环境Tomcat的webapps目录权限不能是777也不能用root用户跑Tomcat。普通用户启动、目录属主设为该用户避免安全问题。很多中间件漏洞都是因为权限太宽被利用的。对于JSP改动不生效的怪问题如果确认reloadable是true还是不行直接停掉Tomcat删除work目录下对应应用的缓存再启动。这个操作我写过太多遍每次都有效——大部分改了没反应的情况都是work缓存和classloader在搞鬼。最后是一条真实经验改任何Tomcat配置之前先把原始文件备份一份cp server.xml server.xml.bak。别嫌啰嗦我见过N次改着改着回不去了、又忘了原配置长什么样的窘境。备份文件用完就删不占地方但能救命。
延伸阅读

更多相关文章

2026/9/16 5:29:24

企业级AI Agent效能管理实战指南:从指标到治理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/16 5:29:24

PLC与DCS的自我防护:从网络分区到控制器加固的工控安全实践

1. 从一次车间瘫掉的排故说起:PLC、DCS的“先天免疫缺陷”上个月普能电控接了一个老车间的改造项目,现场调试刚开始两天就出事了:某条产线的几十台PLC同时报超时,触摸屏全部花屏,现场看到的现象是控制网交换机指示灯疯…

2026/9/16 6:14:26

YuE模型解析:AR-NAR混合架构实现快准兼得的中文生成

1. 项目概述:从“YuE”到可复现的AR-NAR混合建模实践最近在Hugging Face上刷到一个叫“YuE”的模型,点进去发现它既不是传统自回归(AR)语言模型,也不是纯非自回归(NAR)生成器,而是一…

2026/9/16 6:14:26

Node.js系统级文档处理:path、OS、process与child_process实战

1. 这不是“Markdown转HTML”的简单教程,而是一次Node.js系统能力的实战拉练你有没有遇到过这样的场景:一个内部文档系统需要把用户上传的.md文件实时渲染成带样式的HTML页面,但要求不只是加个语法高亮——还要自动提取标题生成目录、把本地图…

2026/9/16 6:14:26

OpenClaw框架解析:模块化AI开发与智能体系统实践

1. 项目背景与核心价值OpenClaw作为当前AI领域备受关注的技术框架,其设计理念和实现方式确实体现了行业发展的某种深层趋势。这个命名颇具意象的项目,本质上是一套面向智能体开发的工具集合,但它的野心远不止于此——从架构设计上就能看出&am…

2026/9/16 6:14:26

JavaWeb蛋糕店系统:三层架构实战与Tomcat9+MySQL5.7部署指南

简介:本资源是一套完整可用的JavaWeb课程设计项目——蛋糕店网站系统源码,面向计算机专业本科生及Java初学者,适用于毕业设计、课程设计与期末大作业等实践场景,解决Web应用开发中商品管理、订单处理与前后端交互等核心问题。压缩…

2026/9/16 6:14:26

基于Docker的分布式爬虫服务架构与部署调优

简介:这是一份基于Docker的分布式爬虫服务项目资料,定位清晰,内容完整,面向Python爬虫开发者、运维人员以及计算机相关专业的在校学生和教师。核心技术采用Go语言实现,配套容器化部署方案,能够帮助读者理解…

2026/9/16 6:09:26

主动配电网多时段故障恢复与孤岛划分MATLAB实现

1. 项目背景与核心价值电力系统故障恢复一直是电网运维中最具挑战性的任务之一。当配电网发生故障时,如何在最短时间内恢复供电、最大限度减少停电范围,直接关系到供电可靠性和用户满意度。传统配电网的故障恢复主要依赖人工调度和预设方案,响…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/16 0:04:09

PHP源码部署实战:从环境配置到运行情侣游戏全攻略

简介:这是一套面向情侣互动场景的PHP完整源码,集成情侣飞行棋、真心话大冒险、情趣骰子等玩法,并内置完整分销制度,可自定义多种返佣比例,源码完全开源无加密,支持微信无感自动授权登录与第三方授权&#x…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码