java bat 启动脚本_解析Tomcat的启动脚本--catalina.bat
概述
Tomcat 的三個最重要的啟動腳本:
startup.bat
catalina.bat
setclasspath.bat
上一篇咱們分析了 startup.bat 腳本
這一篇咱們來分析 catalina.bat 腳本.
至于 setclasspath.bat 這個腳本, 相信看完這一篇, 就可以自己看懂這個腳本了.
可以點擊下載 [ setclasspath.bat 腳本 ]查看附注釋的 setclasspath.bat 腳本
catalina.bat
這個腳本的代碼有點多, 就單獨弄了一篇展示 catalina.bat 腳本中的內容. 點擊 [catalina.bat 腳本 ]下載查看.
下面咱們就按照腳本中的內容一行行的來分析.
@echo off
setlocal
第一塊腳本代碼
rem Suppress Terminate batch job on CTRL+C
if not ""%1"" == ""run"" goto mainEntry
if "%TEMP%" == "" goto mainEntry
if exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.run"
if not exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.Y"
call "%~f0" %*
rem Use provided errorlevel
set RETVAL=%ERRORLEVEL%
del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1
exit /B %RETVAL%
:mainEntry
del /Q "%TEMP%\%~nx0.run" >NUL 2>&1
腳本的作用
判斷用戶是否使用
catalina.bat run
來啟動 Tomcat 的.
如果用戶使用 startup.bat 腳本啟動 Tomcat, 那么這段腳本不會被執(zhí)行.
這段代碼看起來很亂, 慢慢分析.
第一行:
注釋, 意思就是: 禁止使用 CTRL+C 來終止批處理任務, 也不知道是怎么禁止的.
第二行:
if not ""%1"" == ""run"" goto mainEntry
首先明白這里的這個 "%1" 這個變量代表的是什么? 正常情況下, 這個腳本是被 startup.bat 腳本調用的, 被調用的同時傳遞了一個 start 參數(shù)過來(上一篇分析得出的). 在 批處理命令 中 %1 就表示命令之后的第一個參數(shù), 在這里指的就是 start. 所以 "%1" = start. 如果用戶用 catalina.bat run 命令啟動 Tomcat 的話, 那么這里的 "%1" = run.
第三行:
if "%TEMP%" == "" goto mainEntry
這里的 %TEMP% 很有可能被認為是 空, 其實這里可以讀取到系統(tǒng)的環(huán)境變量. 所以, 這里的 %TEMP% 就是系統(tǒng)的環(huán)境變量值, 通常裝完 windows 系統(tǒng)的話, 系統(tǒng)會自動配置上這個環(huán)境變量. 所以這里一般是有值的. 大家可以去系統(tǒng)的環(huán)境變量看一下它指向那個目錄, 一般就是 C:\Users\用戶名\AppData\Local\Temp. 注意: AppData 是一個隱藏目錄.
第四行:
if exist "%TEMP%\%~nx0.run" goto mainEntry
這里又出現(xiàn)了一個新的東西 %~nx0 . 在批處理中, 我們知道 %1 表示的是程序之后的第一個參數(shù), 那么 %0 呢? %0 表示這個可執(zhí)行程序的名稱, %~nx0 的話就是程序的名稱+擴展名
在這里就是 catalina.bat . 大家可以寫一個小腳本(test.bat)驗證一下: (我的腳本放在 D 盤下)
腳本內容:
@echo off
echo "%~nx0"
echo "%1"
執(zhí)行結果:
PS D:\> .\test.bat Hello
"test.bat"
"Hello"
PS D:\>
第五行:
echo Y>"%TEMP%\%~nx0.run"
這段代碼很簡單, 就是寫入字符 Y 到 %TEMP%\catalina.bat.run 文件中.
第六行:
if not exist "%TEMP%\%~nx0.run" goto mainEntry
又判斷了一下 %TEMP%\catalina.bat.run 文件是否存在.
第七行:
echo Y>"%TEMP%\%~nx0.Y"
同第五行, 寫入 Y 到 %TEMP%\catalina.bat.Y . 如果文件不存在, 則新建一個.
第八行:
call "%~f0" %*
這一行有點意思. 又出現(xiàn)了兩個新的東西:
(因為 markdown 語法限制, 把下面代碼寫到代碼塊里)
- "%~f0" : 簡單說就是表示當前命令的絕對路徑.
- "%*" : 我們知道 %1 表示第一個參數(shù), 依次類推, %2 表示第二個.... 那么 %* 就很好理解了, 代表所有參數(shù).
驗證一下
腳本內容:
@echo off
echo "%*"
echo "%~f0"
執(zhí)行結果:
PS D:\> .\test.bat Hello World
"Hello World"
"D:\test.bat"
PS D:\>
那么后面的
之后又通過 call 進行調用.
我們自己寫一個例子, 在 D 盤建立 test.bat 文件, 再建立 catalina.bat.Y 文件
腳本內容:
call "%~f0" %* < D:/catalina.bat.Y
catalina.bat.Y 文件內容
Y
執(zhí)行結果:
........
D:\>call "D:\test.bat" Hello World 0
D:\>call "D:\test.bat" Hello World 0
D:\>call "D:\test.bat" Hello World 0
D:\>call "D:\test.bat" Hello World 0
D:\>call "D:\test.bat" Hello World 0
D:\>call "D:\test.bat" Hello World 0
D:\>call "D:\test.bat" Hello World 0
****** B A T C H R E C U R S I O N exceeds STACK limits ******
Recursion Count=593, Stack Usage=90 percent
****** B A T C H PROCESSING IS A B O R T E D ******
最上面省略了很多重復代碼, 從這里發(fā)現(xiàn)它不斷地調用自己本身, 直到超出了堆棧的限制才停止.
我們如果加上 @echo off 的話
@echo off
call "%~f0" %* < D:/catalina.bat.Y
結果只會出現(xiàn)
D:\>.\test.bat Hello World
****** B A T C H R E C U R S I O N exceeds STACK limits ******
Recursion Count=593, Stack Usage=90 percent
****** B A T C H PROCESSING IS A B O R T E D ******
我們這里只需要明白這些命令的作用就可以, 稍后我們會總結 Tomcat 執(zhí)行這些命令的目的.
第十行:
set RETVAL=%ERRORLEVEL%
我們如果了解 Linux 的話都知道, 每個命令的執(zhí)行都會返回一個執(zhí)行完成之后的退出碼. Linux執(zhí)行完一條命令之后用 echo $? 來查看上一條命令的退出碼. 在 Windows 中也是一樣的, 命令執(zhí)行完之后都有自己的退出碼. 這里的 %ERRORLEVEL% 就是取的上面的 call 命令的退出碼. 賦值給一個變量 RETVAL
第十一行:
del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1
這里又出現(xiàn)了一個 del 命令, 很容易聯(lián)想到 delete, 那么 /Q 是什么意思呢? 靜默刪除, 不會給你任何提示, 就比如 Linux 中的 rm -f 一樣, 這里是刪除 %TEMP%\catalina.bat.Y 這個文件.
后面的 >NUL 2>&1 又是什么意思呢?
于 Linux 中的輸出流的重定向原理是一樣的.
(因為 markdown 語法限制, 把下面代碼寫到代碼塊里)
- >NUL : 表示將輸出重定向到 NUL 中, 你什么也看不到
- 2>&1 : 2:錯誤輸出, &1: 標準輸出, 意思就是將錯誤消息輸出到標準輸出中.
- >NUL 2>&1 : 就是先將錯誤消息輸出到標準輸出中, 然后再輸出到 NUL 中.
第十二行:
exit /B %RETVAL%
退出當前批處理, /B 指定退出時的編號, 把 RETVAL 最為 退出碼, 也就是 call 執(zhí)行的命令 的退出碼.
最后兩行:
:mainEntry
del /Q "%TEMP%\%~nx0.run" >NUL 2>&1
定義一個 mainEntry 標簽, 然后刪除 臨時目錄中的 catalina.bat.run 文件.
總結第一段腳本的功能
簡單說, 這段代碼的作用就是調用本身, 判斷臨時目錄中的文件是否存在來避免二次回調自己. 感覺寫的好復雜.
下面就進入 Tomcat 的正式啟動過程, 并沒有開始執(zhí)行 main 方法
第二段腳本代碼
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
rem Copy CATALINA_BASE from CATALINA_HOME if not defined
if not "%CATALINA_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase
這段腳本還是比較簡單的, 主要是設置了兩個環(huán)境變量 CATALINA_HOME 和 CATALINA_BASE .
如果沒有配置 CATALINA_BASE 環(huán)境變量的話, 直接引用 CATALINA_HOME 的值
靜下心來稍微看一下就懂了.
第三段腳本代碼
rem Ensure that neither CATALINA_HOME nor CATALINA_BASE contains a semi-colon
rem as this is used as the separator in the classpath and Java provides no
rem mechanism for escaping if the same character appears in the path. Check this
rem by replacing all occurrences of ';' with '' and checking that neither
rem CATALINA_HOME nor CATALINA_BASE have changed
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
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
這里主要是判斷 CATALINA_HOME 環(huán)境變量的值 和 CATALINA_BASE 環(huán)境變量的值是否以 分號為結尾, 如果以 分號為結尾的話, 就報錯退出.
第四段腳本代碼
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=
rem Get standard environment variables
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"
:setenvDone
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
設置一個臨時環(huán)境變量: CLASSPATH.
如果 Tomcat 的 bin 目錄下面存在 setnv.bat 腳本的話, 就執(zhí)行它. 通常情況下是沒有的.
繼而又判斷 setclasspath.bat 腳本是否存在, 如果不存在的話, 直接報錯, 停止啟動 Tomcat.
如果存在的話, 就去調用它, 并把 第一個參數(shù)傳進去.
setclasspath.bat 這個腳本主要設置了幾個環(huán)境變量
JAVA_HOME
JRE_HOME
JAVA_ENDORSED_DIRS = %CATALINA_HOME%\endorsed
_RUNJAVA = %JRE_HOME%\bin\java.exe
_RUNJDB = %JAVA_HOME%\bin\jdb.exe
第五段腳本代碼
rem Add on extra jar file to CLASSPATH
rem Note that there are no quotes as we do not want to introduce random
rem quotes into the CLASSPATH
if "%CLASSPATH%" == "" goto emptyClasspath
set "CLASSPATH=%CLASSPATH%;"
:emptyClasspath
set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar"
if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set "CATALINA_TMPDIR=%CATALINA_BASE%\temp"
: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
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar"
goto juliClasspathDone
:juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\tomcat-juli.jar"
:juliClasspathDone
這段代碼主要做了三件事:
把 Tomcat bin 目錄下的 bootstrap.jar 加入到環(huán)境變量中
設置 CATALINA_TMPDIR 環(huán)境變量的值為 Tomcat 目錄下的 temp 目錄
把 Tomcat bin 目錄下的 tomcat-juli.jar 加入到環(huán)境變量中
第六段腳本代碼
if not "%JSSE_OPTS%" == "" goto gotJsseOpts
set JSSE_OPTS="-Djdk.tls.ephemeralDHKeySize=2048"
:gotJsseOpts
set "JAVA_OPTS=%JAVA_OPTS% %JSSE_OPTS%"
rem Register custom URL handlers
rem Do this here so custom URL handles (specifically 'war:...') can be used in the security policy
set "JAVA_OPTS=%JAVA_OPTS% -Djava.protocol.handler.pkgs=org.apache.catalina.webresources"
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"
: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
:noJuliManager
set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%"
主要是追加一系列的啟動參數(shù)到 JAVA_OPTS 這個環(huán)境變量中.
第八段腳本代碼
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%"
主要是打印相關的環(huán)境變量信息.
第九段腳本代碼
set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBUG_OPTS=
set JPDA=
設置一些列的環(huán)境變量:
_RUNJAVA : %JRE_HOME%\bin\java.exe
MAINCLASS : 指定了 Tomcat 的啟動類, 沒錯 main 方法就是在這個類里面.
ACTION : 動作: 就是啟動
SECURITY_POLICY_FILE : 安全策略文件, 如果啟動的時候加上了 -security 參數(shù)的話, 下面會對這個參數(shù)指定到 Tomcat 的 conf 目錄下的 catalina.policy 文件.
JPDA : 這個參數(shù)可以百度一下, 我們平時幾乎用不到.
第十段代碼
if not ""%1"" == ""jpda"" goto 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
:noJpda
好像直接從第一行跳到了最后一行, 沒錯, 一般我沒啟動的時候沒有加 jpda 參數(shù)的話, 這里會直接跳過, 里面的腳本是關于 JPDA 的設置等.
第十一段腳本代碼
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
好似一個 switch 開關.
如果我們用 startup.bat 啟動 Tomcat 的話, 這里的 "%1" 的值是 start
如果通過 catalina.bat run 啟動 Tomcat 的話, 這里的 "%1" 的值是 run
第十二段腳本代碼
: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
首先分析一下其中的兩個 shift 命令
第一個 shift 是把 start 或者 run 參數(shù)移除, 然后下面 還是利用 "%1" 來取參數(shù), 這時候, 取出來的就是參數(shù)列表中的第二個.
第二個 shift 是在第二個參數(shù)移除掉.
我們再來比較一下 start 和 run 的啟動區(qū)別.
差別
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
如果是 startup.bat 腳本啟動的話, 會啟動一個新的 cmd 窗口, 并且把 cmd 的 title 設置為 Tomcat.
如果是 catalina.bat run 啟動的話, 不會新建 cmd 窗口, 也不會設置 cmd 的 title.
最后都跳到了 execCmd 標簽處.
第十三段腳本代碼
:execCmd
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
這里還是利用 "%1" 來取出啟動命令之后的參數(shù), 如果存的話, 追加到 CMD_LINE_ARGS 環(huán)境變量上, 并把這個參數(shù)移除.
通常情況下, 我們這里是不會有什么參數(shù)了, -security 這個參數(shù)我們都不會追加.
繼續(xù)往下走.
第十四段腳本代碼
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%
goto end
很明顯, 我們的 %JPDA% 沒有值, 不會跳轉; 由于我們沒有加 -security 參數(shù), 所以 %SECURITY_POLICY_FILE% 沒有值, 不會跳轉.
下面這段長命令就是來啟動 BootStrap 類, 并把相應的參數(shù)傳進去.
只要把對應的環(huán)境變量替換為它們的值, 就可以解析出這個長命令的內容. 相信你可以的. Be patient!
總結一下
首先判斷一下用戶直接使用 catalina.bat run 來啟動 Tocmat
設置 CATALINA_HOME 和 CATALINA_BASE 環(huán)境變量值
驗證 CATALINA_HOME 和 CATALINA_BASE 環(huán)境變量值的正確性
調用 setnv.bat 腳本
調用 setclasspath.bat 腳本
添加 bootstrap.jar 和 tomcat-juli.jar 到 CLASSPATH 中
設置 CATALINA_TMPDIR 臨時目錄的值為 Tomcat 目錄下的 temp
追加一系列的參數(shù)到 JAVA_OPTS 中
整合相關的啟動信息, 參數(shù)
啟動 Tomcat
以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,有興趣的朋友可以看下上篇文章《解析Tomcat的啟動腳本-startup.bat》
總結
以上是生活随笔為你收集整理的java bat 启动脚本_解析Tomcat的启动脚本--catalina.bat的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python k线顶分型_【缠论】分型、
- 下一篇: python3中多项式创建_机器学习入门