Tomcat啟動過程源碼分析一


前言

  我們都知道只需要在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做了說明。

正式代碼開始在標注第二部分的地方開始。

  1. 設置變量CURRENT_DIR為當前目錄,例如你打開了tomcatbin目錄,那么CURRENT_DIR就指向了bin目錄。
  2. 判斷系統變量CATALINA_HOME如果不是空串,那么就跳轉到gotHome標簽執行,實際上我們很少去設置CATALINA_HOME這個系統變量,所以我們繼續往下看。
  3. 設置CATALINA_HOMECURRENT_DIR指向的目錄,也就是bin目錄。
  4. 判斷CATALINA_HOME\bin\catalina.bat文件是否存在,如果存在就轉向okHome標簽,明顯CATALINA_HOME現在指向的是bin目錄,那么bin\bin\catalina.bat文件是不存在的,所以繼續往下看,不會跳轉到okHome
  5. cd..退出到上一級目錄
  6. 設置CATALINA_HOME指向當前目錄,也就是Tomcat的根目錄。
  7. 進入CURRENT_DIR指向的目錄,也就是bin

繼續看標注第三部分的地方的代碼。

  1. 執行gotHome標簽。
  2. 如果存在CATALINA_HOME%\bin\catalina.bat這個文件就跳轉執行okHome標簽。

繼續看標注第四部分的地方的代碼。

  1. 設置變量EXECUTABLE指向catalina.bat文件

繼續看標注第五部分的地方的代碼。

  1. 雙重保險繼續判斷下EXECUTABLE指向的catalina.bat文件是否存在。存在就跳轉執行okExec標簽。

繼續看標注第六部分的地方的代碼。

  1. set CMD_LINE_ARGS=表示清空變量CMD_LINE_ARGS
  2. 執行setArgs標簽
  3. 第一個變量(%1%)為空字符串,那么就跳轉到doneSetArgs標簽,因為我們是直接運行startup.bat,沒有傳遞任何參數,所以我們應該是跳轉到doneSetArgs標簽,由此也可以猜想出,如果不是使用雙擊執行的話,使用命令行啟動startup.bat那么是可以傳遞參數的。
  4. 跳轉到doneSetArgs,調用EXECUTABLE指向的文件,也就是catalina.bat文件,同時傳遞 start參數,因為CMD_LINE_ARGS為空,所以只傳遞了一個start參數

第七部分

  1. 可以看出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
  1. if not ""%1"" == ""run"" goto mainEntry:第一個參數不是run,就轉向mainEntry標簽,我們傳遞的第一個參數從上面來看是start,所以直接看mainEntry標簽。

  2. 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
  1. 設置CURRENT_DIR為當前目錄bin(假如你是在bin目錄中啟動)
  2. CATALINA_HOME不是空就轉向okHome
  3. 設置CATALINA_HOME指向CURRENT_DIR的目錄,也就是bin目錄。
  4. 如果存在%CATALINA_HOME%\bin\catalina.bat,那么就轉向okHome,否則退出到父目錄,(顯然不存在bin\bin\catalina.bat)
  5. 設置CATALINA_HOME為當前目錄(也就是Tomcat的根目錄)
  6. 進入CURRENT_HOME指向的目錄,也就是bin目錄,執行gotHome標簽
  7. 如果存在%CATALINA_HOME%\bin\catalina.bat,就轉向okHome,現在CATALINA_HOME指向的目錄是Tomcat的安裝目錄,所以\bin\catalina.bat文件是存在的,所以轉向okHome標簽。
  8. 如果CATALINA_BASE變量不是空,就轉向gotBase標簽。(顯然為空)
  9. 設置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
  1. 清空CLASSPATH
  2. 如果不存在%CATALINA_BASE%\bin\setenv.bat文件,那么就轉向checkSetenvHome標簽,我們現在使用的是apache-tomcat-7.0.67,該文件是不存在的,所以轉向checkSetenvHome標簽。
  3. checkSetenvHome標簽,如果存在%CATALINA_HOME%\bin\setenv.bat,那么就調用%CATALINA_HOME%\bin\setenv.bat文件,顯然依舊不存在。
  4. 繼續執行goto gotSetenvBasegotSetenvBase標簽為空,繼續往下執行。

第四部分

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
  1. 如果存在%CATALINA_HOME%\bin\setclasspath.bat,那么就轉向okSetclasspath標簽,(顯然存在)
  2. 設置BASEDIR指向CATALINA_HOME
  3. 調用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
  1. 如果CLASSPATH變量為空,就跳轉到emptyClasspath標簽,由上面能看出來,CLASSPATH變量的確是空的,所以跳轉到emptyClasspath標簽。
  2. 設置CLASSPATH指向%CLASSPATH%%CATALINA_HOME%\BIN\BOOTSTRAP.JAR(也就是TOMCAT安裝目錄下\BIN\BOOTSTRAP.JAR)。
  3. 如果CATALINA_BASE不為空(這里是為空)那么轉向gotBase標簽,gotBase為空標簽,繼續往下執行,設置CATALINA_BASE等於CATALINA_HOME
  4. 如果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%
  1. 如果不存在%CATALINA_BASE%\bin\tomcat-juli.jar那么就跳轉到juliClasspathHome標簽,我們使用的tomcat版本是存在的,所以繼續執行。
  2. 該命令set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar"表示將tomcat-juli.jar的路徑添加到CLASSPATH中。
  3. 跳轉juliClasspathDone標簽,juliClasspathDone是空標簽
  4. 繼續執行,如果LOGGING_CONFIG變量不為空就跳轉到noJuliConfig標簽,否則這只LOGGING_CONFIG=-Dnop
  5. 如果不存在%CATALINA_BASE%\conf\logging.properties,那么就跳轉noJuliConfig標簽,否則設置LOGGING_CONFIG等於-Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties"
  6. noJuliConfig標簽的作用就是設置JAVA_OPTS變量為JAVA_OPTS+LOGGING_CONFIG。( 這里多說一句,我們可以在catalina.bat文件的開始位置添加JAVA_OPTS變量來指定jvm的配置,具體的參數可以自行搜索。)
  7. 繼續往下看,比較類似,如果LOGGING_MANAGER不為空就轉向noJuliManager標簽,否則設置LOGGING_MANAGER值為-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
  8. 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
  1. 打印相關信息,如果第一個參數等於debug,轉到use_jdk標簽,否則打印相關信息,轉向java_dir_displayed標簽,java_dir_displayed還是打印相關信息。
  2. 設置_EXECJAVA等於變量_RUNJAVA.(該變量在setclasspath.bat中設置,值為%JRE_HOME%\bin\java.exe
  3. 設置下相關變量,MAINCLASSACTION。清空SECURITY_POLICY_FILEDEBUG_OPTSJPDA
  4. 如果第一個參數不等於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
  1. 一開始就對第一個參數進行判斷,進而轉向不同的標簽,因為我們第一個參數是start,所以我們直接就轉向了doStart標簽。
  2. doStart標簽,shift,參數左移,如果當前操作系統不是win,就轉向noTitle標簽,如果Title變量為空就將Title設置為Tomcat,設置_EXECJAVA變量為start "%TITLE%" %_RUNJAVA%
  3. 轉向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
  1. 清空CMD_LINE_ARGS變量,如果第一個變量為空,轉向doneSetArgs,運行到這里,因為前面在執行doStart的時候已經執行了shift命令,所以第一個參數已經是空了,所以直接轉向doneSetArgs標簽。
  2. doneSetArgs為空,所以繼續往下執行
  3. 如果JPDA變量不為空,轉向doJpda標簽,實際上我們在第七部分JPDA部分的時候基本上是跳過了jpda,所以該變量是為空的,所以直接繼續執行。
  4. 如果SECURITY_POLICY_FILE變量不為空,就轉向doSecurity標簽,而實際上理由同上SECURITY_POLICY_FILE變量也是空的,所以繼續往下執行。
  5.   %_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!!!

總結:

  1. tomcat啟動入口是startup.bat文件,該文件會設置CATALINA_HOME,CATALINA_BASE等常見變量,並且調用catalina.bat文件,傳遞start參數。
  2. catalina.bat文件,所做的事情就是檢查關鍵文件是否存在,設置關鍵變量,例如CATALINA_HOME,CATALINA_BASE,classpath等等,最后新開一個窗口調用Bootstrap類的main方法,傳遞參數start,並且將一大堆配置傳遞過去。

所以我們想繼續探尋,就需要去Tomcat源碼中找尋 Bootstrap類,繼續查看相關方法!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM