1. 程式人生 > >Tomcat原始碼分析 -- Tomcat的啟動過程(一)

Tomcat原始碼分析 -- Tomcat的啟動過程(一)

本篇結構:

  • 前言
  • bat檔案
  • startup.bat
  • catalina.bat
  • 總結

一、前言

一般啟動tomcat都是找到bin目錄下的startup.bat(windows)下或者startup.sh(linux下),所以要研究tomcat的啟動,startup指令碼是避不開的。那麼下面就來看一看windows下面的startup.bat。

二、bat檔案

要看懂startup.bat,首先得對bat檔案有個基本的瞭解。

bat檔案是dos下的批處理檔案。批處理檔案是無格式的文字檔案,這個檔案的每一行都是一條DOS命令。它的副檔名為 .bat 或 .cmd。在命令提示下鍵入批處理檔案的名稱,或者雙擊該批處理檔案,系統就會呼叫cmd.exe按照該檔案中各個命令出現的順序來逐個執行它們。使用批處理檔案(也被稱為批處理程式或指令碼),可以簡化日常或重複性任務。

批處理簡單語法:

DOS命令 解釋
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視窗

可以參考一下這篇博文:

三、startup.bat

用編輯器開啟startup.bat檔案,內容如下:

@echo off
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 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

set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"

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
: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%

:end

@echo off,此語句常用於開頭,表示不顯示所有的命令列資訊,包括此句。

然後是一大段rem後面的內容,是註釋,對軟體的License做了說明,英文不太好,就不翻譯了。

setlocal,啟動批處理檔案中環境變數的本地化,本地化將持續到出現匹配的endlocal命令或者到達批處理檔案結尾為止。

下面將批處理檔案拆成幾段看:

第一段:判斷CATALINA_HOME是否定義

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%"
  1. 設定變數CURRENT_DIR為當前目錄,一般開啟的就是tomcat的bin目錄,./apache-tomcat-x.x.xx/bin;
  2. 判斷系統變數CATALINA_HOME是不是空串(一般安裝tomcat時,我們都會配置CATALINA_HOME環境變數,不知有沒有印象呢),如果是就跳轉到gotHome標籤執行,假設CATALINA_HOME環境變數沒有定義,就繼續往下;
  3. 設定CATALINA_HOME為CURRENT_DIR指向的目錄,也就是bin目錄(./apache-tomcat-x.x.xx/bin);
  4. 判斷CATALINA_HOME\bin\catalina.bat檔案是否存在,也就是 ./apache-tomcat-x.x.xx/bin/bin/catalina.bat,如果存在就轉向okHome標籤,顯然是不存在的,所以不會跳轉到okHome,繼續往下;
  5. 不存在的話,CATALINA_HOME取上級目錄的值,也就是(./apache-tomcat-x.x.xx/);
  6. 設定CATALINA_HOME指向當前目錄,也就是Tomcat的根目錄;
  7. 進入 CURRENT_DIR(./apache-tomcat-x.x.xx/bin);

第二段:執行gotHome標籤

: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

通過上面的設定,CATALINA_HOME的值已經是: ./apache-tomcat-x.x.xx/,這時判斷./apache-tomcat-x.x.xx/catalina.bat 指令碼是否存在,如果不存在,則輸出一些資訊結束,一般這時是可以找到的,所以跳轉到okHome標籤處;

第三段:執行okHome標籤

:okHome

set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"

設定EXECUTABLE變數指向為catalina.bat指令碼;

第四段:再次檢查catalina.bat是否存在

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

雙重保險繼續判斷下EXECUTABLE指向的catalina.bat檔案是否存在,不存在就輸出提示資訊並且結束,存在就跳轉到okExec標籤處:

第五段:

: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%
  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引數;

**最後:**end標籤

:end

判斷失敗跳轉的標籤,是引數不正確的時候的結束標誌。

四、catalina.bat

如果startup.bat執行正確,就等同於執行catalina.bat start,進入了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" %* <"%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 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

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

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

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

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

if not "%LOGGING_MANAGER%" == "" goto noJuliManager
set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
:noJuliManager

rem Configure JAVA 9 specific start-up parameters
set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.base/java.lang=ALL-UNNAMED"
set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED"

rem Java 9 no longer supports the java.endorsed.dirs
rem system property. Only try to use it if
rem JAVA_ENDORSED_DIRS was explicitly set
rem or CATALINA_HOME/endorsed exists.
set ENDORSED_PROP=ignore.endorsed.dirs
if "%JAVA_ENDORSED_DIRS%" == "" goto noEndorsedVar
set ENDORSED_PROP=java.endorsed.dirs
goto doneEndorsed
:noEndorsedVar
if not exist "%CATALINA_HOME%\endorsed" goto doneEndorsed
set ENDORSED_PROP=java.endorsed.dirs
:doneEndorsed

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=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

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

: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

: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


: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% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -D%ENDORSED_PROP%="%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% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -D%ENDORSED_PROP%="%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% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %JPDA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -D%ENDORSED_PROP%="%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% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %JPDA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -D%ENDORSED_PROP%="%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

和startup.bat指令碼一樣,一段段分析:

第一段:

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. 首先註釋是說,禁止使用 CTRL+C 來終止批處理任務;
  2. if not ""%1"" == ""run"" goto mainEntry,第一個引數不是run,就轉向mainEntry標籤,通過呼叫startup.bat啟動的第一個引數應該是start;
  3. if "%TEMP%" == "" goto mainEntry,%TEMP%是系統的環境變數值,通常裝完windows系統的話, 系統會自動配置上這個環境變數,一般是C:\Users\使用者名稱\AppData\Local\Temp(AppData是一個隱藏資料夾)。這句是說,如果%TEMP%是空串,就轉向mainEntry標籤;
  4. if exist "%TEMP%\%~nx0.run" goto mainEntry, 在批處理中,%1 表示的是程式之後的第一個引數,%0表示這個可執行程式的名稱, %~nx0 的話就是程式的名稱+副檔名,在這裡就是catalina.bat(可以寫一個指令碼測試下);
  5. echo Y>"%TEMP%\%~nx0.run",寫入字元Y到%TEMP%\catalina.bat.run 檔案中;
  6. if not exist "%TEMP%\%~nx0.run" goto mainEntry,又判斷了一下 %TEMP%\catalina.bat.run 檔案是否存在;
  7. echo Y>"%TEMP%\%~nx0.Y",寫入Y到%TEMP%\catalina.bat.Y,如果檔案不存在, 則新建一個;
  8. call "%~f0" %* <"%TEMP%\%~nx0.Y",- “%~f0” : 簡單說就是表示當前命令的絕對路徑。- “%” : %1表示第一個引數,%2表示第二個,%代表所有引數。<”%TEMP%\%~nx0.Y”是讀取 %TEMP%\catalina.bat.Y檔案中的內容,之後又通過call進行呼叫;
  9. set RETVAL=%ERRORLEVEL%,Windows中和linux一樣,命令執行完之後都有自己的退出碼,%ERRORLEVEL%就是取的上面的call 命令的退出碼,賦值給一個變數RETVAL;
  10. del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1,del 命令,很容易聯想到delete, 那麼/Q是什麼意思呢?靜默刪除,不會給出任何提示,就比如Linux中的rm -f 一樣。這裡是刪除%TEMP%\catalina.bat.Y這個檔案。後面的 >NUL 2>&1又是什麼意思呢? >NUL : 表示將輸出重定向到 NUL 中,你什麼也看不到;2>&1 : 2:錯誤輸出,&1: 標準輸出, 意思就是將錯誤訊息輸出到標準輸出中;>NUL 2>&1 : 就是先將錯誤訊息輸出到標準輸出中,然後再輸出到 NUL 中;
  11. exit /B %RETVAL%,退出當前批處理, /B 指定退出時的編號, 把 RETVAL 作為 退出碼, 也就是 call 執行的命令的退出碼;
  12. :mainEntry del /Q “%TEMP%\%~nx0.run” >NUL 2>&1,定義一個 mainEntry 標籤,然後刪除臨時目錄中的 catalina.bat.run 檔案。

這段程式碼的作用就是呼叫本身,判斷臨時目錄中的檔案是否存在來避免二次回撥自己。感覺繞的很暈,迷迷糊糊的,不知道設計者的意圖。有沒有大神可以幫忙解惑?

第二段:

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
  1. set "CURRENT_DIR=%cd%",設定CURRENT_DIR為當前目錄bin(假如你是在bin目錄中啟動);
  2. if not "%CATALINA_HOME%" == "" goto gotHome,CATALINA_HOME不是空就轉向gotHome;
  3. set "CATALINA_HOME=%CURRENT_DIR%",設定CATALINA_HOME指向CURRENT_DIR的目錄,也就是bin目錄;
  4. if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome,如果存在%CATALINA_HOME%\bin\catalina.bat,那麼就轉向okHome,否則退出到父目錄,(顯然不存在bin\bin\catalina.bat);
  5. set "CATALINA_HOME=%cd%",設定CATALINA_HOME為當前目錄(也就是Tomcat的根目錄);
  6. cd "%CURRENT_DIR%",進入CURRENT_HOME指向的目錄,也就是bin目錄,執行gotHome標籤;
  7. if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome,gotHome標籤下,如果存在%CATALINA_HOME%\bin\catalina.bat,就轉向okHome,因為CATALINA_HOME現在指向的目錄是Tomcat的安裝目錄,所以\bin\catalina.bat檔案是存在的,所以轉向okHome標籤;
  8. if not "%CATALINA_BASE%" == "" goto gotBase,如果CATALINA_BASE變數不是空,就轉向gotBase標籤(顯然為空);
  9. set "CATALINA_BASE=%CATALINA_HOME%",設定CATALINA_BASE的值等同與CATALINA_HOME的值(現在CATALINA_BASE也指向的Tomcat的根目錄了)。

這段主要是設定了兩個環境變數 CATALINA_HOME 和 CATALINA_BASE。如果沒有配置 CATALINA_BASE 環境變數的話, 直接引用 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 環境變數的值 和 CATALINA_BASE 環境變數的值是否以分號為結尾,如果以分號為結尾的話,就報錯退出。

第四段:

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

主要是說,如果Tomcat的bin目錄下面存在setenv.bat指令碼的話(setenv.bat是幹什麼的?上面的註釋說是使用者自定義的環境變數,但並不是啟動時必須的定義在setenv.bat中),就執行它,通常情況下是沒有的,繼而又判斷setclasspath.bat指令碼是否存在,如果不存在的話, 直接報錯,停止啟動 Tomcat。如果存在的話,就去呼叫它,並把 第一個引數傳進去。

可以進入setclasspath.bat指令碼看下,主要設定了以下幾個環境變數:

  • JAVA_HOME
  • JRE_HOME
  • JAVA_ENDORSED_DIRS = %CATALINA_HOME%\endorsed
  • _RUNJAVA = %JRE_HOME%\bin\java.exe
  • _RUNJDB = %JAVA_HOME%\bin\jdb.exe

所以這段是設定一個臨時環境變數: CLASSPATH。

第五段:

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 加入到環境變數中;
  • 設定 CATALINA_TMPDIR 環境變數的值為 Tomcat 目錄下的 temp 目錄;
  • 把 Tomcat bin 目錄下的 tomcat-juli.jar 加入到環境變數中;

第六段:

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

if not "%LOGGING_MANAGER%" == "" goto noJuliManager
set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
:noJuliManager

rem Configure JAVA 9 specific start-up parameters
set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.base/java.lang=ALL-UNNAMED"
set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED"

主要是追加一系列的啟動引數到 JAVA_OPTS 這個環境變數中。

第七段:

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=

設定一些環境變數:

  • _RUNJAVA : %JRE_HOME%\bin\java.exe;
  • MAINCLASS : 指定了 Tomcat 的啟動類;
  • ACTION : 動作, 就是啟動;
  • SECURITY_POLICY_FILE : 安全策略檔案,如果啟動的時候加上了 -security 引數的話,下面會對這個引數指定到 Tomcat 的 conf 目錄下的 catalina.policy 檔案;
  • 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=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 引數的話, 這裡會直接跳過,裡面的指令碼是關於 JPDA 的設定等。

第十段:

if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop
if ""%1
            
           

相關推薦

elasticsearch原始碼分析啟動過程

最近開始廣泛的使用elasticsearch,也開始寫一些java程式碼了,為了提高java程式碼能力,也為了更加深入一點了解elasticsearch的內部運作機制,所以開始看一些elasticsearch的原始碼了。對於這種廣受追捧的開源專案,細細品讀一定會受益匪淺,

精盡MyBatis原始碼分析 - SQL執行過程之 Executor

> 該系列文件是本人在學習 Mybatis 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋([Mybatis原始碼分析 GitHub 地址](https://github.com/liu844869663/mybatis-3)、[Mybatis-Spring 原始碼分析 GitHub 地址

Tomcat原始碼分析 -- Tomcat啟動過程

本篇結構: 前言 bat檔案 startup.bat catalina.bat 總結 一、前言 一般啟動tomcat都是找到bin目錄下的startup.bat(windows)下或者startup.sh(linux下),所以要研究tomcat的啟

Spring原始碼解析分析,springMVC專案啟動過程

 springMVC專案啟動過程,分析原始碼。1、環境搭建,這步我就省略細節,只把我的大概環境說下:windows 7 、jdk 8、maven-3.3.9、tomcat 8.5.11、IDEA 2017.1 x64版 具體環境安裝,我就略過,可自行google、baidu安

TOMCAT原始碼分析啟動過程

前言:   本文是我閱讀了TOMCAT原始碼後的一些心得。 主要是講解TOMCAT的系統框架, 以及啟動流程。若有錯漏之處,敬請批評指教!建議:   畢竟TOMCAT的框架還是比較複雜的, 單是從文字上理解, 是不那麼容易掌握TOMCAT的框架的。 所以得實踐、實踐、再實踐。

hadoop啟動過程 NameNode

  一、第一次啟動   NameNode 記憶體 本地磁碟 fsimage edits 格式化HDFS,目的是審查隔行fsimage

springMVC原始碼分析--容器初始化ContextLoaderListener

在spring Web中,需要初始化IOC容器,用於存放我們注入的各種物件。當tomcat啟動時首先會初始化一個web對應的IOC容器,用於初始化和注入各種我們在web執行過程中需要的物件。當tomcat啟動的時候是如何初始化IOC容器的,我們先看一下在web.xml中經常看

seajs原始碼分析-執行機制淺析

前端技術發展簡直是日新月異,隨著angularjs,vuejs,reactjs等等這些框架的不斷興起,轉眼間jquery,seajs,Backbone這些框架已經成了清朝的框架了,再加上es6本身對於模組化的支援,也許,seajs模組化在將來的某天可能會徹底成為

Android4.4.2原始碼分析之WiFi模組

已經寫了幾篇關於Android原始碼的,原始碼程式碼量太大,所以如果想分析某個模組可能不知如何下手,說一下思路 1,分析原始碼英文閱讀能力要夠,想要分析某個模組一般找模組對應的英文,就是模組 2,找到之後首先檢視清單配置檔案Androidmani.fest,找到程式主介面activity 3,通過檢視配置檔

springMVC原始碼分析--HandlerInterceptor攔截器

對SpringMVC有所瞭解的人肯定接觸過HandlerInterceptor攔截器,HandlerInterceptor介面給我們提供了3個方法:(1)preHandle: 在執行controller處理之前執行,返回值為boolean ,返回值為true時接著執行post

springMVC原始碼分析--動態樣式ThemeResolver

Spring MVC中通過ThemeSource介面來提供對動態更換樣式的支援,並提供了ResourceBundleThemeSource這個具體實現類來提供通過properties配置檔案對theme

Activity啟動過程

Launcher啟動Acivity(未啟動Activity所在程序) public abstract class LauncherActivity extends ListActivity { @Override protected voi

spark mllib原始碼分析之L-BFGS

1. 使用 spark給出的example中涉及到LBFGS有兩個,分別是LBFGSExample.scala和LogisticRegressionWithLBFGSExample.scala,第一個是直接使用LBFGS直接訓練,需要指定一系列優化引數,優

MySQL學習筆記——MySQL啟動過程

clas oot handler lis done con replica mut groups 首先去官網或者github下載MySQL5.7的源碼。 官網地址:https://dev.mysql.com/downloads/mysql/ github地址:https:/

一個酷炫的button變化動畫開源庫原始碼分析—Android morph Button

最近很是喜愛一些酷炫的動畫效果,特意在github上找了一些,看看他們是怎麼做到的,做個分析,順便可以對自定義控制元件和動畫有進一步的認識。 先來看下這個庫中button的變化效果是什麼樣的: 是不是很酷炫,而且中間的變化過程很舒服,沒

【Spring Boot原始碼分析】@EnableAutoConfiguration註解@AutoConfigurationImportSelector註解的處理

一、概述 @EnableAutoConfiguration註解是Spring Boot中配置自動裝載的總開關。本文將從@EnableAutoConfiguration入手,嘗試通過原始碼分析增強對Spring Boot的理解。   所用版本:Spring Boot 2.2.0.M5 + Spring

精盡 MyBatis 原始碼分析 - MyBatis 初始化之載入 mybatis-config.xml

> 該系列文件是本人在學習 Mybatis 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋([Mybatis原始碼分析 GitHub 地址](https://github.com/liu844869663/mybatis-3)、[Mybatis-Spring 原始碼分析 GitHub 地址

精盡MyBatis原始碼分析 - SQL執行過程之 StatementHandler

> 該系列文件是本人在學習 Mybatis 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋([Mybatis原始碼分析 GitHub 地址](https://github.com/liu844869663/mybatis-3)、[Mybatis-Spring 原始碼分析 GitHub 地址

精盡MyBatis原始碼分析 - SQL執行過程之 ResultSetHandler

> 該系列文件是本人在學習 Mybatis 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋([Mybatis原始碼分析 GitHub 地址](https://github.com/liu844869663/mybatis-3)、[Mybatis-Spring 原始碼分析 GitHub 地址

精盡MyBatis原始碼分析 - SQL執行過程之延遲載入

> 該系列文件是本人在學習 Mybatis 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋([Mybatis原始碼分析 GitHub 地址](https://github.com/liu844869663/mybatis-3)、[Mybatis-Spring 原始碼分析 GitHub 地址