網(wǎng)Tomcat 10.0.13解壓部署與Jakarta遷移)
簡介Apache Tomcat 10.0.13 Windows 64 位官方版面向 Java Web 開發(fā)者、運維人員及 Servlet/JSP 學習者提供輕量級應用服務器發(fā)行包便于搭建本地運行環(huán)境、部署測試 Web 應用并了解 Tomcat 的核心組件與目錄組織。壓縮包共 644 個文件約 12.58MB以 html 文檔、class 與 java 源碼示例、jsp 頁面、jar 庫為主并含 xml/properties 配置、bat/sh 腳本、圖片與說明文件覆蓋 bin、conf、lib、logs、webapps、work 等典型結構。已有 278 人瀏覽學習。其價值在于保留官方發(fā)行包的原始文件組成便于讀者查閱 Catalina、Jasper、Coyote 相關資料結合配置文件和示例應用理解服務注冊、WAR 部署、安全配置與性能調(diào)優(yōu)思路也適合作為課程實驗、項目聯(lián)調(diào)和版本對照的參考包。1. 一臺沒有外網(wǎng)的 Windows 機器和一份解壓即用的 apache tomcat 10.0.13接手內(nèi)網(wǎng)交付的活最怕對面丟一句「裝個 Tomcat 就行」。機器上沒外網(wǎng)、沒管理員密碼、JDK 還是半年前別人隨手裝的這時候 MSI 安裝包反而成了負擔寫注冊表、搶端口、卸載還留一堆尾巴。apache tomcat 的 windows-x64 壓縮包正好相反解壓、設兩個環(huán)境變量、跑 startup.bat一個能接 WAR 的 Servlet 容器就立在 D 盤了要挪走刪目錄就行。但 10.0.13 卡在一個特殊位置——它實現(xiàn)的是 Jakarta EE 9lib 里只有 jakarta.* 的 API拿它接老項目會當場翻車。這篇按我實際部署的順序把這份包從解壓、Connector 參數(shù)、服務注冊到 javax 遷移和排錯拆一遍適合要在 Windows 上快速起一個容器的人。2. 解壓到跑起來路徑、環(huán)境變量與第一個 WAR這一章的目標很單一從拿到壓縮包到瀏覽器里看到你自己的頁面。步驟不多但 Windows 上幾個老毛病路徑帶空格、JRE_HOME 搶優(yōu)先級、雙擊閃退會讓人卡半小時以上。2.1 解壓路徑與環(huán)境變量的硬約束先說路徑。不要解壓到C:\Program Files\下面一是路徑里有空格某些腳本拼接 classpath 時會斷二是這個目錄受 UAC 保護服務方式啟動時權限容易出問題。我一般固定放D:\server\下目錄名保持壓縮包原名不加中文、不加版本后綴說明REM 解壓后的目錄形如 D:\server\apache-tomcat-10.0.13 REM 先確認 bin 目錄下同時存在 startup.bat 與 tomcat10.exe dir /b D:\server\apache-tomcat-10.0.13\bintomcat10.exe和tomcat10w.exe是這個 windows-x64 包特有的壓縮包里帶了 procrun 包裝器后面注冊 Windows 服務就靠它。如果你下載到的包里沒有這兩個 exe說明拿到的是通用 zip服務注冊會走另一條路。環(huán)境變量只設一個JAVA_HOME指向 JDK 根目錄不是 binsetx JAVA_HOME C:\Program Files\Java\jdk1.8.0_341 /M setx PATH %PATH%;%JAVA_HOME%\bin /M這里有個血淚經(jīng)驗Tomcat 的setclasspath.bat判斷順序是先看 JRE_HOME再看 JAVA_HOME。很多機器上裝著老版本 JRE 并設了JRE_HOME結果啟動日志里的 JVM 版本跟你以為的完全不一樣跑起來報UnsupportedClassVersionError才知道用錯了。要么把JRE_HOME刪掉要么讓它跟JAVA_HOME指向同一個 JDK。10.0.x 這條線最低要 Java 8裝 JDK 8 或 11 都能跑。REM 驗證輸出的路徑必須指向 JDK且位數(shù)與包匹配x64 包里是 64 位包裝器 echo %JAVA_HOME% %JAVA_HOME%\bin\java -version2.2 七個目錄各管什么解壓完先別急著啟動花兩分鐘認一下目錄后面出問題能少走彎路目錄作用能否清空常見誤用bin啟動腳本、service.bat、tomcat10.exe否把setenv.bat放到別處導致不生效confserver.xml、web.xml、context.xml、tomcat-users.xml否直接改web.xml全局配置升級被覆蓋lib容器級 jar含jakarta.servlet-api等否往這里塞業(yè)務 jar和 webapp 類加載器打架logscatalina、localhost、localhost_access_log可出問題只看控制臺不看這里的完整堆棧temp上傳臨時目錄、文件鎖停服后可服務運行中刪導致上傳報錯webapps默認部署目錄可生產(chǎn)環(huán)境留著manager、host-manager、docsworkJSP 編譯產(chǎn)物停服后可改 JSP 不生效時忘了清這里work那一行值得單獨說JSP 第一次訪問會被編譯成 Servlet 落在work\Catalina\localhost\應用名\下改完 JSP 沒反應八成是時間戳沒觸發(fā)重編譯停服刪work目錄再起就好。生產(chǎn)環(huán)境把manager、host-manager、docs、examples四個目錄刪掉這是最省事的一刀。2.3 啟動與部署第一個 WAR啟動有兩種方式區(qū)別很大REM 方式一新開窗口啟動窗口一閃而過時你看不到任何報錯 cd /d D:\server\apache-tomcat-10.0.13\bin startup.bat REM 方式二前臺運行日志直接打在當前窗口排錯首選 cd /d D:\server\apache-tomcat-10.0.13\bin catalina.bat run新手最常踩的坑就是雙擊startup.bat窗口閃一下就沒了然后說「啟動不了」。它其實只是「啟動失敗并關閉了窗口」。用catalina.bat run前臺跑異常堆棧會老老實實打出來??吹絊erver startup in [xxxx] milliseconds才算真正起來了。部署一個 WAR 就是把文件拷進webappsREM 拷貝即部署文件名決定訪問路徑demo-app.war 對應 /demo-app copy /Y D:\build\demo-app.war D:\server\apache-tomcat-10.0.13\webapps\ REM 想看部署過程盯 catalina 日志的最新一份 dir /o-d D:\server\apache-tomcat-10.0.13\logs\catalina.*.log這里有兩個要點。第一Host的autoDeploy和unpackWARs默認都是true容器會自己解包、自己建 Context不需要你寫任何配置第二文件名就是 context pathROOT.war才會映射到根路徑/改名demo-app.war之后訪問地址立刻變成/demo-app很多人改完名忘了這點回頭訪問 8080 根路徑得 404。2.4 起沒起來的三條驗證別靠「瀏覽器沒報錯」判斷按這個順序確認REM 1. 端口在不在監(jiān)聽 netstat -ano | findstr :8080 REM 2. 容器自身是否響應 curl -I http://127.0.0.1:8080/ REM 3. 日志里有沒有 SEVERE findstr /I SEVERE ERROR D:\server\apache-tomcat-10.0.13\logs\catalina.*.logcurl -I返回200或404都說明容器活著404 只是根應用不存在連不上才是容器沒起來。第三步那行findstr最好養(yǎng)成習慣有些應用啟動時報了SEVERE但容器照樣對外服務等到第一次請求才炸。提示確認能用之后把conf\server.xml里port8005的 shutdown 端口和port8080都記下來同一臺機器跑第二個實例時必須改否則第二個實例起不來還不報明顯錯誤。3. server.xml 與 Connector把 8080 調(diào)成能扛事的樣子出廠server.xml是給「跑通」用的不是給「跑穩(wěn)」用的。這一章處理三個真問題Connector 參數(shù)怎么定、應用目錄放哪、怎么變成開機自啟的 Windows 服務。3.1 Connector 的六個必調(diào)參數(shù)先看默認 Connector 長什么樣再逐項改!-- conf/server.xml 中 Service 節(jié)點內(nèi)的 HTTP Connector -- Connector port8080 protocolorg.apache.coyote.http11.Http11NioProtocol address0.0.0.0 connectionTimeout20000 maxThreads400 minSpareThreads50 acceptCount200 maxConnections8192 URIEncodingUTF-8 compressionon compressionMinSize2048 compressibleMimeTypetext/html,text/xml,text/plain,text/css,application/json,application/javascript relaxedQueryChars[]|{}^#x5c;#x60;quot;lt;gt; redirectPort8443 /protocol顯式寫成Http11NioProtocol是為了避免不同 JDK 上自動選擇帶來的行為差異也讓后來接手的人一眼看出用的是 NIO。connectionTimeout屬性本身的默認值是 60000 毫秒出廠文件里寫的是 20000內(nèi)網(wǎng)應用 20 秒夠用對外服務建議拉到 30000 以上否則慢接口會被容器直接掐斷連接。maxThreads是最容易被拍腦袋設的參數(shù)。默認 200它對應的是并發(fā)正在處理的請求數(shù)不是連接數(shù)。經(jīng)驗值是按「單機 CPU 核數(shù) × 25」估一個起點IO 密集的應用可以往上加純計算型的加到 400 反而會因為線程切換變慢。acceptCount是隊列長度線程打滿后新連接堆在這里超過就拒絕內(nèi)網(wǎng)應用 200 足夠公網(wǎng)入口要跟前面的負載均衡策略對上。relaxedQueryChars這一項是真正的后悔藥。Tomcat 從 8.0 開始嚴格校驗請求行里的字符URL 里帶|、{、}、[、]一律返回 400前端把 JSON 直接拼在 query string 里時必翻車。注意 XML 里不能寫裸的、、要用字符引用上面那串#x5c;#x60;quot;lt;gt;就是反斜杠、反引號、雙引號、尖括號的轉(zhuǎn)義寫法抄的時候別漏。3.2 應用目錄放哪三種部署方式的選擇WAR 丟webapps是開發(fā)期最省事的方式但升級 Tomcat 時整個目錄要換應用配置會跟著丟。我一般用第三種方式把配置和容器解耦!-- conf/Catalina/localhost/demo-app.xml文件名即 context path -- ?xml version1.0 encodingUTF-8? Context docBaseD:/apps/demo-app reloadablefalse crossContextfalse Manager pathname / /ContextdocBase指向容器外的目錄用正斜杠或轉(zhuǎn)義反斜杠這樣 Tomcat 升級只要換CATALINA_HOME業(yè)務文件原地不動。reloadablefalse是生產(chǎn)環(huán)境的必須項設成true時容器會不停掃描 class 變更CPU 白燒而且熱加載常常只重載了一半的類引發(fā)各種ClassCastException。Manager pathname /關掉 Session 持久化到磁盤很多莫名其妙的「重啟后拿到臟 Session」就是它引起的如果確實要重啟保留會話就配PersistentManager和FileStore別用默認行為。還有一種是把META-INF/context.xml打進 WAR 里方便但耦合同一份 WAR 想在不同環(huán)境用不同數(shù)據(jù)源就難受了。選型上我的排序是外部 xml WAR 內(nèi)置 直接改server.xml里的 Context。3.3 注冊成 Windows 服務service.bat 的實際用法交付到客戶現(xiàn)場沒人愿意每次登錄服務器手動跑 bat。這個包帶service.bat一條命令注冊成服務cd /d D:\server\apache-tomcat-10.0.13\bin REM 安裝服務并指定初始堆注意服務名只能英文數(shù)字不要帶空格 service.bat install Tomcat10Demo --Startup auto --JvmMs 2048 --JvmMx 4096 REM 啟動并確認狀態(tài) net start Tomcat10Demo sc query Tomcat10Demo REM 改內(nèi)存參數(shù)不用重裝update 即可 service.bat update Tomcat10Demo --JvmMs 2048 --JvmMx 4096 REM 卸載 net stop Tomcat10Demo service.bat remove Tomcat10Demo幾個必須知道的邊界。第一服務注冊時記錄的是當前目錄作為CATALINA_HOME所以一定要先cd到 bin 再執(zhí)行否則服務指向一個不存在的路徑啟動時報錯還很難查。第二服務默認以 LocalSystem 身份運行如果你的應用要訪問網(wǎng)絡共享目錄或者別的用戶配置下的文件權限會跟你在桌面上雙擊啟動時完全不同這類「本地能跑、服務跑不了」的問題十有八九是這里。第三--JvmMx不要超過機器可用內(nèi)存的六成設大了服務啟動直接失敗錯誤只寫在logs\commons-daemon.*.log里事件查看器里看到的只是一個 1067。裝好之后想改 JVM 參數(shù)除了service.bat update也可以直接運行tomcat10w.exe //ES//Tomcat10Demo打開圖形配置界面Java 選項卡里改 Initial/Maximum memory pool。這個 exe 的//ES//參數(shù)后面必須跟準確的服務名名字寫錯就靜默退出什么都不提示。3.4 setenv.batJVM 參數(shù)該寫在哪不要直接改catalina.bat升級一次全丟。正確做法是在bin下新建setenv.bat容器啟動時會自動調(diào)用echo off REM setenv.bat 放在 %CATALINA_BASE%\bin 下不是 CATALINA_HOME set CATALINA_OPTS-Xms2g -Xmx2g -XX:MetaspaceSize256m -XX:MaxMetaspaceSize512m set CATALINA_OPTS%CATALINA_OPTS% -Dfile.encodingUTF-8 -Duser.timezoneAsia/Shanghai set CATALINA_OPTS%CATALINA_OPTS% -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPathD:\logs\heap set JAVA_OPTS%JAVA_OPTS% -Djava.awt.headlesstrueJAVA_OPTS和CATALINA_OPTS的區(qū)別值得記牢JAVA_OPTS會傳給version、stop這些命令CATALINA_OPTS只傳給真正啟動 Tomcat 的那個進程。所以內(nèi)存參數(shù)、GC 參數(shù)放CATALINA_OPTS避免停服務的時候也去申請 2G 堆。-Xms和-Xmx設成一樣大是為了避免運行期擴堆代價是啟動時就把內(nèi)存占住交付到內(nèi)存緊張的機器上要往下調(diào)。HeapDumpOnOutOfMemoryError那個路徑必須先建好目錄容器不會替你創(chuàng)建OOM 時路徑不存在堆轉(zhuǎn)儲就靜默丟了這算是典型的「配了等于沒配」。4. javax 到 jakarta10.0.13 最容易踩的遷移坑這一節(jié)是整份包里最需要提前知道的事。10.0.13 不是「9 的補丁版」它換掉了整個 API 命名空間。4.1 老 WAR 扔進去為什么直接報錯現(xiàn)象很固定應用部署上去日志里出現(xiàn)java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet或者ClassNotFoundException: javax.servlet.Filter又或者更詭異的——類都加載成功了WebServlet注解標注的接口卻 404。原因是 Tomcat 10.0 實現(xiàn) Jakarta EE 9Servlet 規(guī)范從 4.0 升到 5.0包名整體從javax.servlet.*改成jakarta.servlet.*。容器的lib里放的是jakarta.servlet-api根本沒有javax.servlet這個包。注解掃描也一樣它掃的是jakarta.servlet.annotation.WebServlet你代碼里寫的是javax.servlet.annotation.WebServlet容器壓根不認識這個注解于是接口注冊不上部署日志里連個 WARN 都沒有。注意這不是配置問題改任何server.xml都解決不了。要么把應用遷移到 jakarta要么換回 Tomcat 9 那條 javax 線二選一。選型上給個直白的判斷Spring Boot 2.x 及更早打出來的 WAR直接上 Tomcat 9Spring Boot 3.x 或者自己維護 Servlet 代碼的項目用 10.x。中間沒有既省錢又省事的第三條路。4.2 遷移檢查從依賴樹到字節(jié)碼遷移第一步不是改代碼是先摸清有多少 javax 依賴混在里面REM 只篩 servlet / websocket / el 這三類輸出重定向到文件方便比對 mvn -f D:\src\demo-app\pom.xml dependency:tree -Dincludesjavax.servlet:*,javax.websocket:*,javax.el:* D:\build\deps.txt findstr /I javax.servlet jakarta.servlet D:\build\deps.txt輸出里但凡出現(xiàn)javax.servlet:javax.servlet-api、javax.servlet:jstl這類坐標就得換。換的時候注意傳遞依賴很多老框架自己不聲明 servlet-api靠的就是容器提供你換成 jakarta 之后它的內(nèi)部字節(jié)碼還是 javax這時候只能升級框架版本。第二步改源碼。接口方法簽名不變變的只有包名// 遷移后的 Filter包名全部換成 jakarta方法簽名與原來一致 import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; public class DemoFilter implements Filter { Override public void doFilter(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException { // 業(yè)務邏輯完全不用動只有類型所在的包變了 chain.doFilter(request, response); } }全局替換時有個陷阱別把字符串常量里的javax.servlet一起替換掉。有些項目把類名寫進了反射配置或者 XML替換錯了要跑起來才發(fā)現(xiàn)。IDE 的「替換全部」務必限定在*.java的 import 與類型引用范圍內(nèi)替換完git diff掃一眼。第三步改描述符。web.xml的版本號和 schema 位置都要跟著升!-- Servlet 5.0 的命名空間注意是 jakarta.ee不是 java.sun.com -- web-app xmlnshttps://jakarta.ee/xml/ns/jakartaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttps://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd version5.0 display-namedemo-app/display-name /web-appJSP 那邊同樣要動JSTL 的 taglib uri 從http://java.sun.com/jsp/jstl/core改成jakarta.tags.core并且WEB-INF/lib下要放 JSTL 3.0 的實現(xiàn)用 1.2 的實現(xiàn)照樣跑不起來。第四步改完別急著部署先用javap在字節(jié)碼層面復核一遍這一步能提前攔住 90% 的漏網(wǎng)之魚REM 解包 WAR 后用 javap 反查常量池里還有沒有 javax/servlet 引用 cd /d D:\build\demo-app-unpacked\WEB-INF\classes javap -p -c com\example\demo\DemoServlet | findstr /I javax servlet輸出為空才算干凈。要批量查整個目錄寫個循環(huán)把WEB-INF\classes下所有 class 過一遍比人眼翻代碼可靠得多。4.3 兩個命名空間能不能共存這是被問得最多的問題能不能把javax.servlet-api.jar塞進WEB-INF/lib讓老 WAR 直接跑在 10.0.13 上技術上類能加載但沒用。Tomcat 內(nèi)部是按jakarta.servlet.Servlet這個類型去識別和調(diào)用組件的你的 Servlet 實現(xiàn)的是javax.servlet.Servlet兩者不是同一個類型容器在掃描階段就把它當普通類跳過了不會注冊路由不會調(diào)用init。所以你最多能做到「不報 ClassNotFound」但請求還是 404問題從顯式報錯變成了隱形失敗更難查。真要少改代碼有個折中思路是用字節(jié)碼遷移工具批量把 class 里的javax/servlet常量池引用改成jakarta/servletWAR 解包、批量改、重新打包。這條路對純 Servlet/JSP 項目有效對依賴了框架內(nèi)部反射、動態(tài)代理、OSGi 的應用就不一定了框架內(nèi)部可能硬編碼了類名字符串改字節(jié)碼改不到。所以我的建議是能升級依賴就升級不能升級就老老實實選 Tomcat 9別在中間地帶耗時間。5. 排查清單五個把服務卡在啟動階段的坑下面五條是我在 Windows 上部署 Tomcat 時反復遇到的按「現(xiàn)象 → 原因 → 解決」記遇到同類問題可以直接對號。5.1 雙擊 startup.bat 窗口一閃而過現(xiàn)象雙擊startup.bat黑窗口閃一下就關閉瀏覽器訪問 8080 無響應logs目錄里也沒新日志。原因startup.bat會用start新開一個窗口跑catalina.bat如果JAVA_HOME沒設、指向 JRE、或者位數(shù)不匹配64 位包裝器配 32 位 JVM子進程立刻退出父窗口也就跟著關了錯誤信息全丟在已經(jīng)關閉的子窗口里。解決永遠用catalina.bat run前臺啟動看第一手報錯。如果是JRE_HOME干擾臨時set JRE_HOME再啟動驗證如果是位數(shù)問題%JAVA_HOME%\bin\java -version輸出里會帶64-Bit字樣對不上就換 JDK。5.2 8080 端口被占用或第二個實例起不來現(xiàn)象啟動日志末尾報Address already in use: bind或者機器上跑第二個 Tomcat 時明明改了 8080 還是失敗。原因除了 HTTP 的 8080server.xml里還有shutdown端口 8005 和 AJP 端口 8009三個都要改只改一個必然沖突。另外 Windows 上 8080 常被別的服務占著。解決先查占用再動手REM 查出占用 8080 的進程 PID確認是不是自己的舊實例 netstat -ano | findstr :8080 tasklist | findstr 上一步查到的PID REM 確認可以殺再殺別誤殺別的服務 taskkill /PID PID /F多個實例共存時把shutdown端口改成 8006、8007 依次遞增AJP 那段在 10.0.x 里默認是注釋掉的不用管。5.3 中文亂碼但只在某一種場景下亂現(xiàn)象控制臺啟動日志里中文變問號或者頁面正常但 GET 參數(shù)亂碼或者反過來頁面亂碼日志正常。原因三種亂碼三個根因??刂婆_亂碼是 cmd 的代碼頁默認 936和 JVM 的file.encoding不一致GET 參數(shù)亂碼在 Tomcat 8 之后已經(jīng)很少見因為URIEncoding默認就是 UTF-8問題通常出在前端沒做encodeURIComponent或者網(wǎng)關轉(zhuǎn)了一道響應亂碼則是Content-Type里沒帶charsetUTF-8。解決setenv.bat里加-Dfile.encodingUTF-8cmd 里執(zhí)行chcp 65001再看日志。響應側統(tǒng)一在過濾器里設response.setCharacterEncoding(UTF-8)或者由框架的編碼過濾器兜底。注意別在server.xml里再手動寫URIEncodingISO-8859-1那是給老版本擦屁股的寫法現(xiàn)在寫上去只會制造新問題。5.4 請求返回 400日志說 Invalid character現(xiàn)象某些帶參數(shù)的 URL 一訪問就 400日志里是Invalid character found in the request target把參數(shù)刪掉就正常。原因Tomcat 嚴格按 RFC 校驗請求行|、{、}、[、]、反斜杠這些字符默認不允許出現(xiàn)在 URL 里。前端把 JSON、數(shù)組參數(shù)直接拼進 query string 時必中。解決在 Connector 上加relaxedQueryChars路徑里也可能出現(xiàn)的話再加relaxedPathChars。寫的時候注意 XML 轉(zhuǎn)義、、都要用字符引用否則server.xml直接解析失敗容器起不來報的還是一句很含糊的Error parsing server.xml。改完先跑catalina.bat run確認能起來再掛服務。5.5 服務裝上了net start 報 1067 或 1053現(xiàn)象service.bat install提示成功sc query能看到服務但net start立刻失敗事件查看器里只有「進程意外終止」。原因service.bat注冊時記錄的是執(zhí)行命令那一刻的當前目錄。如果你在別的目錄執(zhí)行或者先裝服務再挪了 Tomcat 目錄服務指向的路徑就是錯的。另一個常見原因是--JvmMx設得超過物理內(nèi)存JVM 起不來服務管理器只報一個籠統(tǒng)的錯誤碼。解決錯誤細節(jié)在logs\commons-daemon.YYYY-MM-DD.log里第一行通常就寫著真正的失敗原因。路徑錯就service.bat remove后cd到 bin 重裝內(nèi)存參數(shù)錯就service.bat update往下調(diào)。順手確認服務名沒寫錯tomcat10w.exe //ES//服務名里的名字必須和sc query看到的完全一致。6. 進階日志切分、訪問日志與一份程序跑多實例容器能跑只是及格線交付到現(xiàn)場還得管兩件事日志別把磁盤寫爆以及一臺機器上跑多個環(huán)境。Tomcat 的日志走 JULI配置在conf\logging.properties。出廠配置里catalina日志是按天滾動的但保留天數(shù)是 90 天且單個文件不限大小業(yè)務日志一多l(xiāng)ogs目錄很快就上 G。我的習慣是把關鍵幾行調(diào)成下面這樣重點在maxDays和rotatable# conf/logging.properties 片段 # 1catalina.org.apache.juli.AsyncFileHandler.level FINE 1catalina.org.apache.juli.AsyncFileHandler.directory ${catalina.base}/logs 1catalina.org.apache.juli.AsyncFileHandler.prefix catalina. 1catalina.org.apache.juli.AsyncFileHandler.suffix .log 1catalina.org.apache.juli.AsyncFileHandler.maxDays 15 1catalina.org.apache.juli.AsyncFileHandler.rotatable true 1catalina.org.apache.juli.AsyncFileHandler.bufferSize 8192訪問日志默認不開需要自己在Host里加 Valve。開了之后每一條請求一行排查慢請求、確認 caller IP 全靠它!-- conf/server.xml 的 Host 節(jié)點內(nèi)rotatable 讓文件按天切 -- Valve classNameorg.apache.catalina.valves.AccessLogValve directorylogs prefixaccess. suffix.log pattern%{yyyy-MM-dd HH:mm:ss}t %h %l %u quot;%rquot; %s %b %D rotatabletrue /pattern里的%D是處理耗時毫秒這個字段比什么都值錢接口慢不慢一眼就看出來。%h記客戶端 IP前面掛了反向代理的話要換成%{X-Forwarded-For}i否則所有請求的 IP 都是代理機的。多實例的做法是拆CATALINA_BASECATALINA_HOME只留一份程序每個實例目錄下復制conf、logs、temp、webapps、work五個目錄然后寫個啟動腳本分別指定REM 實例一端口 8080指向自己的 base 目錄 set CATALINA_HOMED:\server\apache-tomcat-10.0.13 set CATALINA_BASED:\server\instance-a call %CATALINA_HOME%\bin\catalina.bat runCATALINA_BASE下的bin\setenv.bat才是這個實例真正生效的那份很多人改了CATALINA_HOME\bin\setenv.bat發(fā)現(xiàn)不生效就是被 base 目錄里的同名文件覆蓋了。最后說個驗證習慣。壓測不用上大工具ab -n 2000 -c 100 http://127.0.0.1:8080/demo-app/api/ping打一輪同時開個窗口看jstack里線程池的狀態(tài)http-nio-8080-exec-*線程數(shù)量一直貼著maxThreads上限說明該調(diào)線程或者查慢 SQL 了而不是繼續(xù)往上加線程數(shù)。從那以后我每次落地一個新的 Tomcat 目錄都會先用catalina.bat run前臺跑一遍、看到Server startup in那行再掛服務配置錯在啟動階段就暴露比事后翻日志省事得多。希望幫到你。本文還有配套的精品資源點擊獲取