Windows下,Tomcat可以以服务形式启动、停止,也可以执行脚本启动(startup.bat)、停止(shutdown.bat)。执行startup.bat时会调用catalina.bat,catalina.bat脚本又会调用setclasspath.bat进行java class path指定。上篇讲了startup.bat启动代码实现,本文将剖析catalina.bat的代码实现。
版本:8.0.36
安装目录:E:\tomcat8
由于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
-
因为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类。