windows下tomcat8啓動腳本代碼剖析--catalina.bat

Windows下,Tomcat可以以服務形式啓動、停止,也可以執行腳本啓動(startup.bat)、停止(shutdown.bat)。執行startup.bat時會調用catalina.bat,catalina.bat腳本又會調用setclasspath.bat進行java class path指定。上篇講了startup.bat啓動代碼實現,本文將剖析catalina.bat的代碼實現。

1、tomcat版本及安裝目錄

版本:8.0.36
安裝目錄:E:\tomcat8

2、catalina.bat代碼剖析

由於catalina.bat腳本代碼較多,爲了講解方便,代碼說明統一採用高級語言註釋//,並移除原代碼中的很多rem英文註釋。

@echo off  		//關閉回顯
setlocal		//開啓局部變量

//startup.bat調用過來第一個參數爲start, 跳到mainEntry
if not ""%1"" == ""run"" goto mainEntry 	
if "%TEMP%" == "" goto mainEntry			//TEMP爲空執行mainEntry,如:C:\Users\ADMINI~1\AppData\Local\Temp
if exist "%TEMP%\%~nx0.run" goto mainEntry	//%~nx爲腳本文件名:catalina.bat
echo Y>"%TEMP%\%~nx0.run"					//臨時目錄下生成.run文件,內容爲Y
if not exist "%TEMP%\%~nx0.run" goto mainEntry  //文件不存在,執行mainEntry
echo Y>"%TEMP%\%~nx0.Y"						//臨時目錄下生成.Y文件,內容爲Y

//調用catalina.bat,%*所有參數空格分割的拼接串,如:e:\tomcat8\bin\catalina.bat arg1 arg2 Y
call "%~f0" %* <"%TEMP%\%~nx0.Y"			

set RETVAL=%ERRORLEVEL%				//腳本調用返回碼
del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1	//刪除文件,/Q 靜默刪除,2>&1 成功和錯誤信息都輸出到 NUL
exit /B %RETVAL%

:mainEntry
//安靜刪除temp目錄下的catalina.bat.run文件,成功和錯誤信息都輸出到nul
del /Q "%TEMP%\%~nx0.run" >NUL 2>&1	
set "CURRENT_DIR=%cd%"	// 設置CURRENT_DIR=當前目錄
//CATALINA_HOME爲空,跳到gotHome
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"	//設置CATALINA_HOME=CURRENT_DIR
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome	//存在catalina.bat,執行okHome
cd ..	//跳到上層目錄
set "CATALINA_HOME=%cd%"	//CATALINA_HOME當前目錄
cd "%CURRENT_DIR%"			//進入CURRENT_DIR

:gotHome
// 存在catalina.bat,執行okHome
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
rem Copy CATALINA_BASE from CATALINA_HOME if not defined
if not "%CATALINA_BASE%" == "" goto gotBase	//CATALINA_BASE不爲空,執行gotBase
set "CATALINA_BASE=%CATALINA_HOME%"			//變量賦值

//bat逐行執行,okHome執行完畢後執行gotBase
:gotBase
// CATALINA_HOME=E:\tomcat8 沒有分號 執行 homeNoSemicolon
if "%CATALINA_HOME%" == "%CATALINA_HOME:;=%" goto homeNoSemicolon
echo Using CATALINA_HOME:   "%CATALINA_HOME%"
echo Unable to start as CATALINA_HOME contains a semicolon (;) character
goto end

:homeNoSemicolon
// CATALINA_BASE=E:\tomcat8 沒有分號 執行 baseNoSemicolon
if "%CATALINA_BASE%" == "%CATALINA_BASE:;=%" goto baseNoSemicolon
echo Using CATALINA_BASE:   "%CATALINA_BASE%"
echo Unable to start as CATALINA_BASE contains a semicolon (;) character
goto end

:baseNoSemicolon
rem Ensure that any user defined CLASSPATH variables are not used on startup,
rem but allow them to be specified in setenv.bat, in rare case when it is needed.
set CLASSPATH=
// 沒有setenv.bat文件,執行checkSetenvHome
if not exist "%CATALINA_BASE%\bin\setenv.bat" goto checkSetenvHome
call "%CATALINA_BASE%\bin\setenv.bat"
goto setenvDone

:checkSetenvHome
if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat"

// 順序執行,checkSetenvHome執行完執行setenvDone
:setenvDone
// 存在setclasspath.bat腳本,執行okSetclasspath
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
// 調用setclasspath.bat腳本,e:tomcat8\bin\setclasspath.bat start
// setclasspath.bat, 主要設置java_home,jre_home,java.exe路徑
call "%CATALINA_HOME%\bin\setclasspath.bat" %1
if errorlevel 1 goto end	//errorlevel非0表示出錯,結束腳本

//CLASSPATH爲空,跳到emptyClasspath
if "%CLASSPATH%" == "" goto emptyClasspath
set "CLASSPATH=%CLASSPATH%;"

:emptyClasspath
//設置classpath,臨時目錄
set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar"
if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set "CATALINA_TMPDIR=%CATALINA_BASE%\temp"

// 順序執行,emptyClasspath執行完執行gotTmpdir
// gotTmpdir執行到最後,跳到juliClasspathDone
:gotTmpdir
rem Add tomcat-juli.jar to classpath
rem tomcat-juli.jar can be over-ridden per instance
if not exist "%CATALINA_BASE%\bin\tomcat-juli.jar" goto juliClasspathHome
//設置變量爲日誌jar,tomcat-juli.jar路徑
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar"
goto juliClasspathDone

:juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\tomcat-juli.jar"

//由gotTmpdir跳過來
:juliClasspathDone
if not "%JSSE_OPTS%" == "" goto gotJsseOpts
set JSSE_OPTS="-Djdk.tls.ephemeralDHKeySize=2048"	//本例因爲JSSE_OPTS爲空,會在此處賦值

// 順序執行,juliClasspathDone後執行gotJsseOpts
:gotJsseOpts
set "JAVA_OPTS=%JAVA_OPTS% %JSSE_OPTS%"
if not "%LOGGING_CONFIG%" == "" goto noJuliConfig
set LOGGING_CONFIG=-Dnop
if not exist "%CATALINA_BASE%\conf\logging.properties" goto noJuliConfig
set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties"

// 順序執行,gotJsseOpts後執行noJuliConfig
:noJuliConfig
set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%"
if not "%LOGGING_MANAGER%" == "" goto noJuliManager
set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager

// 順序執行,noJuliConfig後執行noJuliManager,%1=start
:noJuliManager
set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%"
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	//本例會執行java_dir_displayed

:use_jdk
echo Using JAVA_HOME:       "%JAVA_HOME%"

// 由noJuliManager跳過來
: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=

if not ""%1"" == ""jpda"" goto noJpda	//%1=start, 所以會執行noJpda
set JPDA=jpda
if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport
set JPDA_TRANSPORT=dt_socket
:gotJpdaTransport
if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress
set JPDA_ADDRESS=localhost:8000
:gotJpdaAddress
if not "%JPDA_SUSPEND%" == "" goto gotJpdaSuspend
set JPDA_SUSPEND=n
:gotJpdaSuspend
if not "%JPDA_OPTS%" == "" goto gotJpdaOpts
set JPDA_OPTS=-agentlib:jdwp=transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND%
:gotJpdaOpts
shift

// 由java_dir_displayed跳過來,%1=start,因此會跳到doStart
:noJpda
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

echo Usage:  catalina ( commands ... )
echo commands:
echo   debug             Start Catalina in a debugger
echo   debug -security   Debug Catalina with a security manager
echo   jpda start        Start Catalina under JPDA debugger
echo   run               Start Catalina in the current window
echo   run -security     Start in the current window with security manager
echo   start             Start Catalina in a separate window
echo   start -security   Start in a separate window with security manager
echo   stop              Stop Catalina
echo   configtest        Run a basic syntax check on server.xml
echo   version           What version of tomcat are you running?
goto end

: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

// 由noJpda跳過來
:doStart
shift		// %2 變成 %1
if "%TITLE%" == "" set TITLE=Tomcat		// 設置cmd命令框標題爲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

:doStop
shift
set ACTION=stop
set CATALINA_OPTS=
goto execCmd

:doConfigTest
shift
set ACTION=configtest
set CATALINA_OPTS=
goto execCmd

:doVersion
%_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util.ServerInfo
goto end

// 由doStart跳過來
:execCmd
rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=

// execCmd 順序執行而來
:setArgs
// startup.bat start 帶入的參數在之前的shift 操作中已經移出,此處%1爲空,跳到doneSetArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs

//由setArgs跳過來
:doneSetArgs
rem Execute Java with the applicable properties
if not "%JPDA%" == "" goto doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity
//執行 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%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_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end

:doSecurity
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %JPDA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %JPDA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end

:end

3、代碼說明

因爲catalina.bat腳本確實有點長,裏面的跳轉比較多,看起來不夠直接,這兒列出catalina.bat腳本的跳轉關係,以startup.bat 調用catalina.bat start爲例。

if not ""%1"" == ""run"" goto mainEntry

:mainEntry
if not "%CATALINA_HOME%" == "" goto gotHome

:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome

:okHome
set "CATALINA_BASE=%CATALINA_HOME%"
順序執行gotBase

:gotBase
if "%CATALINA_HOME%" == "%CATALINA_HOME:;=%" goto homeNoSemicolon

:homeNoSemicolon
if "%CATALINA_BASE%" == "%CATALINA_BASE:;=%" goto baseNoSemicolon

:baseNoSemicolon
if not exist "%CATALINA_BASE%\bin\setenv.bat" goto checkSetenvHome
順序執行setenvDone

:setenvDone
if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath

:okSetclasspath
if "%CLASSPATH%" == "" goto emptyClasspath

:emptyClasspath
按順序執行 gotTmpdir

:gotTmpdir
//E:\tomcat8\bin\tomcat-juli.jar
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar"
goto juliClasspathDone

:juliClasspathDone
set JSSE_OPTS="-Djdk.tls.ephemeralDHKeySize=2048"

:gotJsseOpts
會順序執行到 :noJuliConfig

:noJuliConfig
會順序執行到 :noJuliManager

:noJuliManager
會順序執行到goto java_dir_displayed

:java_dir_displayed
if not ""%1"" == ""jpda"" goto noJpda, 會跳到noJpda

:noJpda
if ""%1"" == ""start"" goto doStart, 會跳到doStart

:doStart
if not ""%1"" == ""-security"" goto execCmd, 會跳到execCmd

:execCmd
set CMD_LINE_ARGS=

:setArgs
if ""%1""=="""" goto doneSetArgs

:doneSetArgs
//start "Tomcat" "E:\software\java\jdk1.8.0_92\bin\java.exe"  "-Djdk.tls.ephemeralDHKeySize=2048" -Djava.util.logging.config.file="E:\tomcat8\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager   -Djava.endorsed.dirs="E:\tomcat8\endorsed" -classpath "E:\tomcat8\bin\bootstrap.jar;E:\tomcat8\bin\tomcat-juli.jar" -Dcatalina.base="E:\tomcat8" -Dcatalina.home="E:\tomcat8" -Djava.io.tmpdir="E:\tomcat8\temp" org.apache.catalina.startup.Bootstrap  start
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end

腳本最後調用的是:

start "Tomcat" "E:\software\java\jdk1.8.0_92\bin\java.exe"  "-Djdk.tls.ephemeralDHKeySize=2048" -Djava.util.logging.config.file="E:\tomcat8\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager   -Djava.endorsed.dirs="E:\tomcat8\endorsed" -classpath "E:\tomcat8\bin\bootstrap.jar;E:\tomcat8\bin\tomcat-juli.jar" -Dcatalina.base="E:\tomcat8" -Dcatalina.home="E:\tomcat8" -Djava.io.tmpdir="E:\tomcat8\temp" org.apache.catalina.startup.Bootstrap  start

啓動java進程,運行org.apache.catalina.startup.Bootstrap類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章