前言
我們都知道只需要在Tomcat中bin
目錄下啟動startup.bat/sh
,那么整個Tomcat就可以啟動起來給我們提供服務,我們不免心生疑問啟動startup.bat/sh
以后,Tomcat到底是如何啟動的,那么下面我們就來一步一步分析吧!
啟動第一步(startup.bat
)
既然啟動tomcat需要啟動startup.bat/sh
,那么我們就從startup.bat/sh
開始看起吧。筆者因操作系統使用的win系統,所以就只看了startup.bat
,實際上startup.sh
是給linux系統准備的啟動程序並且兩者所做的事情完全相同,只是為不同的系統准備的而已,所以只需要查看一個即可。
.bat
文件是Windows中雙擊的可執行文件。為了大家能夠讀懂上面的程序,需要先學習一些批處理文件的基本命令。
rem: 該命令用於注釋,rem起始的行不會作為代碼執行
pause: 該命令用於暫停正在執行的批處理文件,並且提示用戶按鍵,然后程序繼續執行
echo: 該命令用於在dos控制台顯示一段文本,相當於print,如果想要顯示環境變量需要在環境變量前后加上%,例如顯示操作系統 echo %OS%
echo off: 該命令可以防止將批處理文件中的具體命令打印出來,而只會輸出執行結果。
@echo off:該命令與echo off相同,唯一的區別在於 @echo off不僅會隱藏具體命令還會連'echo off'這個自身命令也隱藏起來。
set: 設置環境變量,例如 set A = 100 設置A變量為100
label: 使用 ':'(冒號)來設置一個標簽,供給goto命令使用,例如":init"代表一個init標簽。
goto: 該命令使正在執行的命令強制跳轉到他指定的標簽。例如我需要跳轉指定A標簽下的命令,如下:goto A
not: 該命令用來取反,相當於邏輯非。
if: 該命令表示判斷
exist: 該命令通常用來測試文件是否存在,一般和if一起使用
shift: 該命令用來將參數后移一位即將%2%賦值給%1%,%3%賦值給%2%,也可以理解為參數列表左移即刪除現有參數列表的第一位。
call: 該命令用來調用另外一條命令。
setLocal: 該命令表示該批處理文件中修改的環境變量只在本文件中起作用,或者直到endLocal命令出現,被修改的環境變量才恢復原狀。
start: 重新開啟一個dos窗口。
使用編輯器打開bin/startup.bat
我們可以看到如下的代碼:
@echo off
rem 第一部分
rem Licensed to the Apache Software Foundation (ASF) under one or more
rem contributor license agreements. See the NOTICE file distributed with
rem this work for additional information regarding copyright ownership.
rem The ASF licenses this file to You under the Apache License, Version 2.0
rem (the "License"); you may not use this file except in compliance with
rem the License. You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.
rem ---------------------------------------------------------------------------
rem Start script for the CATALINA Server
rem ---------------------------------------------------------------------------
setlocal
rem 第二部分
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%"
rem 第三部分
: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
rem 第四部分
:okHome
set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"
rem 第五部分
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
rem 第六部分
: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%
rem 第七部分
:end
分析
在標注第一部分
的地方全是注釋,對軟件的License做了說明。
正式代碼開始在標注第二部分
的地方開始。
- 設置變量
CURRENT_DIR
為當前目錄,例如你打開了tomcat
的bin
目錄,那么CURRENT_DIR
就指向了bin
目錄。 - 判斷系統變量
CATALINA_HOME
如果不是空串,那么就跳轉到gotHome
標簽執行,實際上我們很少去設置CATALINA_HOME
這個系統變量,所以我們繼續往下看。 - 設置
CATALINA_HOME
為CURRENT_DIR
指向的目錄,也就是bin
目錄。 - 判斷
CATALINA_HOME\bin\catalina.bat
文件是否存在,如果存在就轉向okHome
標簽,明顯CATALINA_HOME
現在指向的是bin
目錄,那么bin\bin\catalina.bat
文件是不存在的,所以繼續往下看,不會跳轉到okHome
。 cd..
退出到上一級目錄- 設置
CATALINA_HOME
指向當前目錄,也就是Tomcat
的根目錄。 - 進入
CURRENT_DIR
指向的目錄,也就是bin
。
繼續看標注第三部分
的地方的代碼。
- 執行
gotHome
標簽。 - 如果存在
CATALINA_HOME%\bin\catalina.bat
這個文件就跳轉執行okHome
標簽。
繼續看標注第四部分
的地方的代碼。
- 設置變量
EXECUTABLE
指向catalina.bat
文件
繼續看標注第五部分
的地方的代碼。
- 雙重保險繼續判斷下
EXECUTABLE
指向的catalina.bat
文件是否存在。存在就跳轉執行okExec
標簽。
繼續看標注第六部分
的地方的代碼。
set CMD_LINE_ARGS=
表示清空變量CMD_LINE_ARGS
。- 執行
setArgs
標簽 - 第一個變量(
%1%)
為空字符串,那么就跳轉到doneSetArgs
標簽,因為我們是直接運行startup.bat
,沒有傳遞任何參數,所以我們應該是跳轉到doneSetArgs
標簽,由此也可以猜想出,如果不是使用雙擊執行的話,使用命令行啟動startup.bat
那么是可以傳遞參數的。 - 跳轉到
doneSetArgs
,調用EXECUTABLE
指向的文件,也就是catalina.bat
文件,同時傳遞start
參數,因為CMD_LINE_ARGS
為空,所以只傳遞了一個start
參數
第七部分
- 可以看出
end
標簽是很多,判斷失敗跳轉的標簽,是參數不正確的時候的結束標志。
啟動第二步(catalina.bat
)
繼續上面分析,在所有參數正確的條件下,startup.bat
文件會設置CATALINA_HOME
變量,並且調用catalina.bat
文件,同時傳遞參數start
,那么我們繼續打開catalina.bat
看看,這個文件又做了什么。
catalina.bat
代碼如下:
@echo off
rem 第一部分
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" %* <"%TEMP%\%~nx0.Y"
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
rem 第二部分
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 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.
rem 第三部分
set CLASSPATH=
rem Get standard environment variables
if "%CATALINA_BASE%" == "" goto gotSetenvHome
if exist "%CATALINA_BASE%\bin\setenv.bat" call "%CATALINA_BASE%\bin\setenv.bat"
goto gotSetenvBase
:gotSetenvHome
if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat"
:gotSetenvBase
rem 第四部分
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
set "BASEDIR=%CATALINA_HOME%"
call "%CATALINA_HOME%\bin\setclasspath.bat" %1
if errorlevel 1 goto end
rem 第五部分
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_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase
if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set "CATALINA_TMPDIR=%CATALINA_BASE%\temp"
:gotTmpdir
rem 第六部分
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
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%
rem 第七部分
rem ----- Execute The Requested Command ---------------------------------------
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=
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=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
rem 第八部分
if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop
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 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
:doStart
shift
if not "%OS%" == "Windows_NT" goto noTitle
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
goto gotTitle
:noTitle
set _EXECJAVA=start %_RUNJAVA%
:gotTitle
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
:doVersion
%_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util.ServerInfo
goto end
rem 第九部分
: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
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
: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% %CATALINA_OPTS% %JPDA_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% %CATALINA_OPTS% %JPDA_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
一眼看上去代碼真的很多,也很亂,也有很多看不懂的東西,好吧,我們慢慢來分析,一步一步來。
第一部分
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" %* <"%TEMP%\%~nx0.Y"
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
-
if not ""%1"" == ""run"" goto mainEntry
:第一個參數不是run
,就轉向mainEntry
標簽,我們傳遞的第一個參數從上面來看是start
,所以直接看mainEntry
標簽。 -
del /Q "%TEMP%\%~nx0.run" >NUL 2>&1
,第一眼看上去什么鬼,不要方,乍一看好像是個刪除的命令,但是后面的%~nx0.run >NUL 2>&1
完全看不懂。遇到這種情況第一步可以先做個測試,我們新建一個test.bat
文件,里面寫上如下命令,看看會打印出來什么。我們如果是雙擊執行的話,需要在下一行加上pause
來停止下窗口便於觀看。test.bat
@echo off
echo 'TEMP' = %TEMP%
echo '%~nx0.run' = %~nx0.run
pause
可以看到如下輸出
'TEMP' = C:\Users\ADMINI~1\AppData\Local\Temp
'test.bat.run' = \test.bat.run
由此可見 TEMP
目錄指向了我們環境變量的臨時文件目錄,%~nx0
則指向了我們本身運行的文件名,不包含全目錄,單純的文件名,那么>NUL 2>&1
這個東西,我們只好查閱相關資料了.
>NUL
表示前面命令執行拋出的異常將不顯示/Q 安靜模式。刪除全局通配符時,不要求確認
1是標准輸出
2是錯誤輸出
和 >> 都是輸出重定向符號。標准輸出默認是打印到控制台,如果要導入到文件,就需要使用>或>>。> 會覆蓋已有的文件內容,而>>會附加到已有內容之后。
< 和 << 是輸入重定向符號。從文件中讀取內容。
2>&1 是把錯誤輸出導入(合並)到標准輸出流中
所以mainEntry
這個標簽的作用就是,刪除臨時目錄下的catalina.bat.run
文件,如果出錯也不提示。第一部分的其他行代碼基本大同小異,也可以繼續通過echo
命令來測試,第一部分的整體作用其實是針對ctrl+c
命令終止進程所做的操作而已。可以參看上面的注釋rem Suppress Terminate batch job on CTRL+C
第二部分
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
- 設置
CURRENT_DIR
為當前目錄bin
(假如你是在bin
目錄中啟動) CATALINA_HOME
不是空就轉向okHome
- 設置
CATALINA_HOME
指向CURRENT_DIR
的目錄,也就是bin
目錄。 - 如果存在
%CATALINA_HOME%\bin\catalina.bat
,那么就轉向okHome
,否則退出到父目錄,(顯然不存在bin\bin\catalina.bat
) - 設置
CATALINA_HOME
為當前目錄(也就是Tomcat的根目錄) - 進入
CURRENT_HOME
指向的目錄,也就是bin
目錄,執行gotHome
標簽 - 如果存在
%CATALINA_HOME%\bin\catalina.bat
,就轉向okHome
,現在CATALINA_HOME
指向的目錄是Tomcat的安裝目錄,所以\bin\catalina.bat
文件是存在的,所以轉向okHome
標簽。 - 如果
CATALINA_BASE
變量不是空,就轉向gotBase
標簽。(顯然為空) - 設置
CATALINA_BASE
的值等同與CATALINA_HOME
的值。(現在CATALINA_BASE
也指向的Tomcat的根目錄了)
第三部分
set CLASSPATH=
rem Get standard environment variables
if "%CATALINA_BASE%" == "" goto gotSetenvHome
if exist "%CATALINA_BASE%\bin\setenv.bat" call "%CATALINA_BASE%\bin\setenv.bat"
goto gotSetenvBase
:gotSetenvHome
if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat"
:gotSetenvBase
- 清空CLASSPATH
- 如果不存在
%CATALINA_BASE%\bin\setenv.bat
文件,那么就轉向checkSetenvHome
標簽,我們現在使用的是apache-tomcat-7.0.67
,該文件是不存在的,所以轉向checkSetenvHome
標簽。 checkSetenvHome
標簽,如果存在%CATALINA_HOME%\bin\setenv.bat
,那么就調用%CATALINA_HOME%\bin\setenv.bat
文件,顯然依舊不存在。- 繼續執行
goto gotSetenvBase
,gotSetenvBase
標簽為空,繼續往下執行。
第四部分
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
set "BASEDIR=%CATALINA_HOME%"
call "%CATALINA_HOME%\bin\setclasspath.bat" %1
if errorlevel 1 goto end
- 如果存在
%CATALINA_HOME%\bin\setclasspath.bat
,那么就轉向okSetclasspath
標簽,(顯然存在) - 設置
BASEDIR
指向CATALINA_HOME
- 調用
setclasspath.bat
並且傳遞第一個參數(start
),有興趣的同學可以自行查看setclasspath.bat
文件做了什么,其實就是設置了JAVA_HOME
,JRE_HOME
等變量的值。
第五部分
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_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase
if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set "CATALINA_TMPDIR=%CATALINA_BASE%\temp"
:gotTmpdir
- 如果
CLASSPATH
變量為空,就跳轉到emptyClasspath
標簽,由上面能看出來,CLASSPATH
變量的確是空的,所以跳轉到emptyClasspath
標簽。 - 設置
CLASSPATH
指向%CLASSPATH%%CATALINA_HOME%\BIN\BOOTSTRAP.JAR
(也就是TOMCAT安裝目錄下\BIN\BOOTSTRAP.JAR
)。 - 如果
CATALINA_BASE
不為空(這里是為空)那么轉向gotBase
標簽,gotBase
為空標簽,繼續往下執行,設置CATALINA_BASE
等於CATALINA_HOME
- 如果
CATALINA_TMPDIR
變量不為空(運行到這里的時候為空)轉向gotTmpdir
標簽,否則設置CATALINA_TMPDIR
的值為CATALINA_BASE\temp
,也就是Tomcat安裝目錄下的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
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%
- 如果不存在
%CATALINA_BASE%\bin\tomcat-juli.jar
那么就跳轉到juliClasspathHome
標簽,我們使用的tomcat版本是存在的,所以繼續執行。 - 該命令
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar"
表示將tomcat-juli.jar
的路徑添加到CLASSPATH
中。 - 跳轉
juliClasspathDone
標簽,juliClasspathDone
是空標簽 - 繼續執行,如果
LOGGING_CONFIG
變量不為空就跳轉到noJuliConfig
標簽,否則這只LOGGING_CONFIG=-Dnop
- 如果不存在
%CATALINA_BASE%\conf\logging.properties
,那么就跳轉noJuliConfig
標簽,否則設置LOGGING_CONFIG
等於-Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties"
noJuliConfig
標簽的作用就是設置JAVA_OPTS
變量為JAVA_OPTS
+LOGGING_CONFIG
。( 這里多說一句,我們可以在catalina.bat文件的開始位置添加JAVA_OPTS變量來指定jvm的配置,具體的參數可以自行搜索。)- 繼續往下看,比較類似,如果
LOGGING_MANAGER
不為空就轉向noJuliManager
標簽,否則設置LOGGING_MANAGER
值為-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
noJuliManager
標簽,將LOGGING_MANAGER
添加到JAVA_OPTS
變量。
第七部分
rem ----- Execute The Requested Command ---------------------------------------
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=
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=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
- 打印相關信息,如果第一個參數等於
debug
,轉到use_jdk
標簽,否則打印相關信息,轉向java_dir_displayed
標簽,java_dir_displayed
還是打印相關信息。 - 設置
_EXECJAVA
等於變量_RUNJAVA
.(該變量在setclasspath.bat
中設置,值為%JRE_HOME%\bin\java.exe
。 - 設置下相關變量,
MAINCLASS
,ACTION
。清空SECURITY_POLICY_FILE
,DEBUG_OPTS
,JPDA
。 - 如果第一個參數不等於
jpda
,轉向noJpda
標簽。noJpda
為空標簽,因為第一個參數是start
所以,繼續往下看
第八部分
if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop
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 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
:doStart
shift
if not "%OS%" == "Windows_NT" goto noTitle
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
goto gotTitle
:noTitle
set _EXECJAVA=start %_RUNJAVA%
:gotTitle
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
:doVersion
%_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util.ServerInfo
goto end
- 一開始就對第一個參數進行判斷,進而轉向不同的標簽,因為我們第一個參數是
start
,所以我們直接就轉向了doStart
標簽。 doStart
標簽,shift
,參數左移,如果當前操作系統不是win
,就轉向noTitle
標簽,如果Title
變量為空就將Title
設置為Tomcat
,設置_EXECJAVA
變量為start "%TITLE%" %_RUNJAVA%
。- 轉向
gotTitle
標簽,如果第一個參數不等於-security
,轉向execCmd
標簽。
執行到這里大概可以看出前面的都是在做准備工作,設置好各種參數,判斷等等。終於要開始調用執行命令了。
第九部分
rem 第九部分
: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
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
: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% %CATALINA_OPTS% %JPDA_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% %CATALINA_OPTS% %JPDA_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
- 清空
CMD_LINE_ARGS
變量,如果第一個變量為空,轉向doneSetArgs
,運行到這里,因為前面在執行doStart
的時候已經執行了shift
命令,所以第一個參數已經是空了,所以直接轉向doneSetArgs
標簽。 doneSetArgs
為空,所以繼續往下執行- 如果
JPDA
變量不為空,轉向doJpda
標簽,實際上我們在第七部分JPDA
部分的時候基本上是跳過了jpda
,所以該變量是為空的,所以直接繼續執行。 - 如果
SECURITY_POLICY_FILE
變量不為空,就轉向doSecurity
標簽,而實際上理由同上SECURITY_POLICY_FILE
變量也是空的,所以繼續往下執行。 -
%_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%
終於等到這一行命令了,參考上面所有的變量這行命令在作者的機器上可以翻譯為
start "Tomcat" "D:\WorkSoftware\Java\jdk1.7.0_13\bin\java" -Djava.util.logging.config.file="E:\cccccccccccccccccccccccc\tomcat7.0\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs="E:\cccccccccccccccccccccccc\tomcat7.0\endorsed" -classpath "E:\cccccccccccccccccccccccc\tomcat7.0\bin\bootstrap.jar;E:\cccccccccccccccccccccccc\tomcat7.0\bin\tomcat-juli.jar" -Dcatalina.base="E:\cccccccccccccccccccccccc\tomcat7.0" -Dcatalina.home="E:\cccccccccccccccccccccccc\tomcat7.0" -Djava.io.tmpdir="E:\cccccccccccccccccccccccc\tomcat7.0\temp" org.apache.catalina.startup.Bootstrap start
這句命令的意思就是新開一個窗口,窗口名字叫做Tomcat 使用java.exe,各種參數配置balabla,最后調用org.apache.catalina.startup.Bootstrap類,(類入口當然是main方法)傳遞參數為start!!!
總結:
- tomcat啟動入口是
startup.bat
文件,該文件會設置CATALINA_HOME
,CATALINA_BASE
等常見變量,並且調用catalina.bat
文件,傳遞start
參數。 catalina.bat
文件,所做的事情就是檢查關鍵文件是否存在,設置關鍵變量,例如CATALINA_HOME
,CATALINA_BASE
,classpath
等等,最后新開一個窗口調用Bootstrap
類的main
方法,傳遞參數start
,並且將一大堆配置傳遞過去。
所以我們想繼續探尋,就需要去Tomcat源碼中找尋 Bootstrap類,繼續查看相關方法!