1 Tomcat 基本知識
首先介紹一些 Tomcat 的基本知識,防止有純小白看的雲裡霧裡的。
下面這張圖是一個下載好二進位制版的的 Tomcat ,直接解壓得到的,雖然版本是 9.x ,但是這個目錄結構和 8.5 是一致的,不影響介紹。
- bin : 主要用來存放一些指令碼檔案,一種格式是 sh 的是在 Linux 使用的指令碼,另一種格式是 bat 的是在 Windows 中使用的指令碼。
- conf : 主要用來存放一些 Tomcat 的配置檔案,有 xml 格式的也有 properties 格式的。
- lib : 用來存放一些 Tomcat 執行時所需要的 jar 包。
- logs : 日誌目錄。
- temp : 存放一些執行過程中產生的臨時檔案。
- webapps : 這個應該很熟悉,主要用來存放應用程式,可以是 war 包或者是 jar 包。
- work : 主要用來存放 Tomcat 在執行時的編譯後檔案。清空work目錄,然後重啟 Tomcat ,可以達到清除快取的作用。
現在的 IDE(Integrated Development Environment)
工具可以直接將 Tomcat 配置在工具中,比如最常用的 Eclipse 和 IDEA ,啟動 Tomcat 的時候只需要點一下按鈕就可以啟動,實際上這兩個 IDE 工具只是幫我們呼叫了 Tomcat 的啟動指令碼。
Tomcat 的各種指令碼都放在 bin 這個目錄下,我們開啟看一下:
可以輕易的找到兩個啟動指令碼 startup.bat
和 startup.sh
。一個是 Windows 下的指令碼,一個 Linux 下的。
同樣,還可以看到兩個停止指令碼 shutdown.bat
和 shutdown.sh
。
這是在 Tomcat 的二進位制包中,我們還可以看下原始碼包下是什麼樣的。
可以看到,基本上該有的都有,最重要的啟停指令碼都還在。
既然我現在是在 Windows 環境下,那麼啟動就從 startup.bat
看起。
2 Tomcat 啟動第一步:startup.bat
第一個開啟 startup.bat
這個啟動指令碼,看下里面寫了啥具體,這段指令碼不長,我把裡面的內容摘出來:
setlocal
rem Guess CATALINA_HOME if not defined
set "CURRENT_DIR=%cd%"
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome
set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"
rem Check that target executable exists
if exist "%EXECUTABLE%" goto okExec
echo Cannot find "%EXECUTABLE%"
echo This file is needed to run this program
goto end
:okExec
rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
call "%EXECUTABLE%" start %CMD_LINE_ARGS%
:end
最開始一大段的 rem 註釋我沒摘,只摘了最後一部分會執行的內容。
第一段是在設定當前的 CATALINA_HOME
的環境變數,如果沒有設定的話,會將當前執行指令碼的目錄作為該環境變數的值,然後跳轉到 :okHome
那裡。
接下來設定了 EXECUTABLE
的路徑是 %CATALINA_HOME%\bin\catalina.bat
。
然後開始驗證驗證設定的 EXECUTABLE
中的 catalina.bat
這個檔案存不存在,如果不存在的話直接結束,如果存在的話接著往下走。
接下來是將執行指令碼前設定的其他引數儲存到 CMD_LINE_ARGS
這個變數中,然後在最後執行了 catalina.bat
這個檔案,跟了兩個引數,第一個是 start
,第二個就是剛才儲存的變數 CMD_LINE_ARGS
。
這種指令碼程式碼建議放在編輯器裡看,千萬不要使用那個 Windows 自帶的記事本,用那玩意看估計大多數人直接就看懵了。
我通常是放在 VSCode 中看,會自動對程式碼進行高亮展示,給大家看下上面這段指令碼放在 VSCode 中的樣子:
可以看到,正常註釋變灰,關鍵字變藍高亮,並且跳轉語句直接變橙色,非常方便我們閱讀。
3 Tomcat 啟動第二步:catalina.bat
這個指令碼太長了,我就單純的擷取比較重要的進行介紹。
set "CURRENT_DIR=%cd%"
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome
在最開頭的地方,校驗 CATALINA_HOME
是否存在,如果不存在,則設定 CATALINA_HOME
為當前路徑。
接著下面設定了一下 CATALINA_BASE
這個變數。
if not "%CATALINA_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase
接下來到了一個重點內容,判斷 setclasspath.bat
是否存在,如果存在的話就執行一下:
rem Get standard Java environment variables
if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath
echo Cannot find "%CATALINA_HOME%\bin\setclasspath.bat"
echo This file is needed to run this program
goto end
:okSetclasspath
call "%CATALINA_HOME%\bin\setclasspath.bat" %1
if errorlevel 1 goto end
這個檔案實際上是校驗是否設定了 JAVA_HOME
或者 JRE_HOME
的環境變數,如果沒有設定則會在控制檯列印對應的資訊。
接下來是有關於 CLASSPATH
的設定和校驗,然後是一堆變數的設定和校驗,無需關注,接著使用 echo
列印了一些資訊:
echo Using CATALINA_BASE: "%CATALINA_BASE%"
echo Using CATALINA_HOME: "%CATALINA_HOME%"
echo Using CATALINA_TMPDIR: "%CATALINA_TMPDIR%"
if ""%1"" == ""debug"" goto use_jdk
echo Using JRE_HOME: "%JRE_HOME%"
goto java_dir_displayed
:use_jdk
echo Using JAVA_HOME: "%JAVA_HOME%"
:java_dir_displayed
echo Using CLASSPATH: "%CLASSPATH%"
各種比較重要的變數在這裡進行了一些列印,接下來又設定了一些比較重要的變數:
set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBUG_OPTS=
set JPDA=
這裡的 _EXECJAVA
實際上是我們在 JAVA_HOME
或者是 JRE_HOME
中 bin 下面的 java.exe
。
這裡出現的 _RUNJAVA
變數,是在上面的 setclasspath.bat
那個指令碼中進行設定的。
而這個 MAINCLASS
的值是 org.apache.catalina.startup.Bootstrap
,這個是我們第一篇文章啟動 Tomcat 時候的那個類,不知道各位還有印象不。
接下來設定了一個變數 ACTION
的動作時 start
,用屁股想想應該是啟動的意思。
然後對引數進行了一次判斷:
if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop
if ""%1"" == ""configtest"" goto doConfigTest
if ""%1"" == ""version"" goto doVersion
如果沒有其他引數做覆蓋,這裡的引數就是上面設定的 start
,直接跳轉到最後的 doStart
去了,不過可以看到, Tomcat 啟動可以接受的引數有 debug
, run
, start
, stop
, configtest
和 version
,我們平時在 IDE 工具裡用的比較多的應該有 debug
, run
, start
, stop
, 剩下的兩個至少我是基本上沒有使用過,如果不是今天看到這裡了,我都不知道 Tomcat 還能有 configtest
和 version
這兩個引數。
:doDebug
shift
set _EXECJAVA=%_RUNJDB%
set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\java"
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd
:doRun
shift
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd
:doStart
shift
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd
上面這一段就是我們最常用的三種啟動方式,從指令碼上來看, debug
比 run
單純的多設定了兩個變數 _EXECJAVA
和 DEBUG_OPTS
,而 start
則是多了一個 TITLE
的判斷。
接著往下看,基本上就已經到了這個指令碼的最底部,這裡執行了一句話,也是核心的一句話:
%_EXECJAVA% %CATALINA_LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -D%ENDORSED_PROP%="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
_EXECJAVA
是我們剛才說的那個 java.exe
,然後是各種執行時引數和系統屬性,最後面的 MAINCLASS
,也就是 org.apache.catalina.startup.Bootstrap
,接著是 CMD_LINE_ARGS
,這也是一個命令引數,就是 main
方法上的那個 args
引數,最後一個引數是 ACTION
也就是 start
。
最後歸根結底就是一句話,執行 Bootstrap
裡面的 main
方法,別看這些個指令碼寫了一大堆,主要工作就是在校驗環境配置以及一些基礎系統設定和一些執行時引數的設定。
4 小結
指令碼整體來講不難,而且每段指令碼上面都已經有了簡單的英文註釋,簡明扼要的寫清楚了這一段指令碼在做什麼,稍微瞭解一些基礎的 DOS 命令,都可以進行閱讀。
至於其他的指令碼可以大致瀏覽下,基本上兜兜轉轉最後還是會回到 catalina.bat
這個指令碼,而在這個指令碼中,最後肯定會執行 Bootstrap
裡面的 main
方法。
在 Windows 系統中,使用的是 bat 指令碼,在 Linux 系統中,就會使用 sh 指令碼,這個本質上沒有什麼大的差別,整體原理都是一樣的,有興趣的同學可以自己研究下 sh 指令碼,就當學 shell 語法了。