java tomcat源码_详解Tomcat系列(一)-从源码分析Tomcat的启动
在整個(gè)Tomcat系列文章講解之前, 我想說(shuō)的是雖然整個(gè)Tomcat體系比較復(fù)雜, 但是Tomcat中的代碼并不難讀, 只要認(rèn)真花點(diǎn)功夫, 一定能啃下來(lái).
由于篇幅的原因, 很難把Tomcat所有的知識(shí)點(diǎn)都放到同一篇文章中, 我將把Tomcat系列文章分為Tomcat的啟動(dòng), Tomcat中各模塊的介紹和Tomcat中的設(shè)計(jì)模式三部分, 歡迎閱讀與關(guān)注.
一:通過(guò)idea搭建Tomcat源碼閱讀環(huán)境
首先我們到Tomcat的官網(wǎng)(http://tomcat.apache.org/)上下載Tomcat的源碼, 本文分析的Tomcat版本是Tomcat7.0.94.
進(jìn)入官網(wǎng)后在左邊的目錄中選擇Tomcat7, 然后到頁(yè)面末尾的源碼區(qū)進(jìn)行下載.
下載完成后打開idea, 選擇File->Open->選擇tomcat的源碼目錄
然后到項(xiàng)目配置中設(shè)置JDK和源碼目錄. File->Project Structure->project SDK
設(shè)置完畢后我們便可以開始愉快的源碼閱讀之旅了. (eclipse或其他ide搭建環(huán)境的思路也是差不多的, 可以摸索一下).
二:startup源碼分析
當(dāng)我們初學(xué)tomcat的時(shí)候, 肯定先要學(xué)習(xí)怎樣啟動(dòng)tomcat. 在tomcat的bin目錄下有兩個(gè)啟動(dòng)tomcat的文件, 一個(gè)是startup.bat, 它用于windows環(huán)境下啟動(dòng)tomcat; 另一個(gè)是startup.sh, 它用于linux環(huán)境下tomcat的啟動(dòng). 兩個(gè)文件中的邏輯是一樣的, 我們只分析其中的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
.bat文件中@echo是打印指令, 用于控制臺(tái)輸出信息, rem是注釋符.
跳過(guò)開頭的注釋, 我們來(lái)到配置CATALINA_HOME的代碼段, 執(zhí)行startup.bat文件首先會(huì)設(shè)置CATALINA_HOME.
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
先通過(guò)set指令把當(dāng)前目錄設(shè)置到一個(gè)名為CURRENT_DIR的變量中,
如果系統(tǒng)中配置過(guò)CATALINA_HOME則跳到gotHome代碼段. 正常情況下我們的電腦都沒(méi)有配置CATALINA_HOME, 所以往下執(zhí)行, 把當(dāng)前目錄設(shè)置為CATALINA_HOME.
然后判斷CATALINA_HOME目錄下是否存在catalina.bat文件, 如果存在就跳到okHome代碼塊.
在okHome中, 會(huì)把catalina.bat文件的的路徑賦給一個(gè)叫EXECUTABLE的變量, 然后會(huì)進(jìn)一步判斷這個(gè)路徑是否存在, 存在則跳轉(zhuǎn)到okExec代碼塊, 不存在的話會(huì)在控制臺(tái)輸出一些錯(cuò)誤信息.
在okExec中, 會(huì)把setArgs代碼塊的返回結(jié)果賦值給CMD_LINE_ARGS變量, 這個(gè)變量用于存儲(chǔ)啟動(dòng)參數(shù).
setArgs中首先會(huì)判斷是否有參數(shù), (if ""%1""==""""判斷第一個(gè)參數(shù)是否為空), 如果沒(méi)有參數(shù)則相當(dāng)于參數(shù)項(xiàng)為空. 如果有參數(shù)則循環(huán)遍歷所有的參數(shù)(每次拼接第一個(gè)參數(shù)).
最后執(zhí)行call "%EXECUTABLE%" start %CMD_LINE_ARGS%, 也就是說(shuō)執(zhí)行catalina.bat文件, 如果有參數(shù)則帶上參數(shù).
總結(jié): startup.bat文件實(shí)際上就做了一件事情: 啟動(dòng)catalina.bat.
ps: 這樣看來(lái), 在windows下啟動(dòng)tomcat未必一定要通過(guò)startup.bat, 用catalina.bat start也是可以的.
catalina.bat源碼分析
為了不讓文章看起來(lái)太臃腫, 這里就不先把整個(gè)文件貼出來(lái)了, 我們逐塊代碼進(jìn)行分析.
跳過(guò)開頭的注釋, 我們來(lái)到下面的代碼段:
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
大多情況下我們啟動(dòng)tomcat都沒(méi)有設(shè)置參數(shù), 所以直接跳到mainEntry代碼段, 刪除了一個(gè)臨時(shí)文件后, 繼續(xù)往下執(zhí)行.
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%"
可以看到這段代碼與startup.bat中開頭的代碼相似, 在確定CATALINA_HOME下有catalina.bat后把CATALINA_HOME賦給變量CATALINA_BASE.
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"
上面這段代碼依次執(zhí)行了setenv.bat和setclasspath.bat文件, 目的是獲得CLASSPATH, 相信會(huì)Java的同學(xué)應(yīng)該都會(huì)在配置環(huán)境變量時(shí)都配置過(guò)classpath, 系統(tǒng)拿到classpath路徑后把它和CATALINA_HOME拼接在一起, 最終定位到一個(gè)叫bootstrap.jar的文件. 雖然后面還有很多代碼, 但是這里必須暫停提示一下: bootstrap.jar將是我們啟動(dòng)tomcat的環(huán)境.
接下來(lái)從gotTmpdir代碼塊到noEndorsedVar代碼塊進(jìn)行了一些配置, 由于不是主要內(nèi)容暫且跳過(guò).
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
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
接下來(lái), 我們能看到一些重要的信息, 其中的重點(diǎn)是:
set _EXECJAVA=%_RUNJAVA%, 設(shè)置了jdk中bin目錄下的java.exe文件路徑.
set MAINCLASS=org.apache.catalina.startup.Bootstrap, 設(shè)置了tomcat的啟動(dòng)類為Bootstrap這個(gè)類. (后面會(huì)分析這個(gè)類)
set ACTION=start設(shè)置tomcat啟動(dòng)
大家可以留意這些參數(shù), 最后執(zhí)行tomcat的啟動(dòng)時(shí)會(huì)用到.
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
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
接著判斷第一個(gè)參數(shù)是否是jpda, 是則進(jìn)行一些設(shè)定. 而正常情況下第一個(gè)參數(shù)是start, 所以跳過(guò)這段代碼. 接著會(huì)判斷第一個(gè)參數(shù)的內(nèi)容, 根據(jù)判斷, 我們會(huì)跳到doStart代碼段. (有余力的同學(xué)不妨看下debug, run等啟動(dòng)方式)
: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
可以看到doStart中無(wú)非也是設(shè)定一些參數(shù), 最終會(huì)跳轉(zhuǎn)到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
可以看到這段代碼也是在拼接參數(shù), 把參數(shù)拼接到一個(gè)叫CMD_LINE_ARGS的變量中, 接下來(lái)就是catalina最后的一段代碼了.
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
跳過(guò)前面兩行判斷后, 來(lái)到了關(guān)鍵語(yǔ)句:
%_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%
_EXECJAVA也就是_RUNJAVA, 也就是平時(shí)說(shuō)的java指令, 但在之前的doStart代碼塊中把_EXECJAVA改為了start "%TITLE%" %_RUNJAVA%, 所以系統(tǒng)會(huì)另啟一個(gè)命令行窗口, 名字叫Tomcat.
在拼接一系列參數(shù)后, 我們會(huì)看見(jiàn)%MAINCLASS%, 也就是org.apache.catalina.startup.Bootstrap啟動(dòng)類, 拼接完啟動(dòng)參數(shù)后, 最后拼接的是%ACTION%, 也就是start.
總結(jié): catalina.bat最終執(zhí)行了Bootstrap類中的main方法.
ps: 分析完整個(gè)catalina.bat我們發(fā)現(xiàn)我們可以通過(guò)設(shè)定不同的參數(shù)讓tomcat以不同的方式運(yùn)行. 在ide中我們是可以選擇debug等模式啟動(dòng)tomcat的, 也可以為其配置參數(shù), 在catalina.bat中我們看到了啟動(dòng)tomcat背后的運(yùn)作流程.
Tomcat啟動(dòng)流程分析
上面我們從運(yùn)行startup.bat一路分析來(lái)到Bootstrap的啟動(dòng), 下面我們先對(duì)Tomcat中的組件進(jìn)行一次總覽. 由于篇幅的原因, tomcat中各個(gè)模塊的關(guān)系將留到下一篇文章敘述, 這里先給出一張tomcat中各模塊的關(guān)系圖.
從圖中我們可以看出tomcat中模塊還是挺多的, 那么tomcat是如何啟動(dòng)這些模塊的呢? 請(qǐng)看下面這張示意圖.
由圖中我們可以看到從Bootstrap類的main方法開始, tomcat會(huì)以鏈的方式逐級(jí)調(diào)用各個(gè)模塊的init()方法進(jìn)行初始化, 待各個(gè)模塊都初始化后, 又會(huì)逐級(jí)調(diào)用各個(gè)模塊的start()方法啟動(dòng)各個(gè)模塊. 下面我們通過(guò)部分源碼看一下這個(gè)過(guò)程.
首先我們來(lái)到Bootstrap類的main方法
public static void main(String args[]) {
if (daemon == null) {
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
// When running as a service the call to stop will be on a new
// thread so make sure the correct class loader is used to prevent
// a range of class not found exceptions.
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
try {
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null == daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
} catch (Throwable t) {
// Unwrap the Exception for clearer error reporting
// 省略
System.exit(1);
}
}
我們可以看到, Bootstrap類首先會(huì)創(chuàng)建一個(gè)本類對(duì)象, 然后調(diào)用init()方法進(jìn)行初始化. 執(zhí)行完init()方法后會(huì)判斷啟動(dòng)參數(shù)的值, 由于我們采取默認(rèn)的啟動(dòng)方式, 所以main方法的參數(shù)是start, 會(huì)進(jìn)入下面的判斷代碼塊
else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
可以看到在設(shè)置等待后, 調(diào)用了本類對(duì)象的load()方法. 我們跟進(jìn)查看load()方法的源碼.
private void load(String[] arguments)
throws Exception {
// Call the load() method
String methodName = "load";
Object param[];
Class> paramTypes[];
if (arguments==null || arguments.length==0) {
paramTypes = null;
param = null;
} else {
paramTypes = new Class[1];
paramTypes[0] = arguments.getClass();
param = new Object[1];
param[0] = arguments;
}
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled())
log.debug("Calling startup class " + method);
method.invoke(catalinaDaemon, param);
}
可以看到方法的最后通過(guò)反射的方式調(diào)用了成員變量catalinaDaemon的load()方法. 通過(guò)跟蹤源碼我們可以看到catalinaDaemon是Bootstrap類的一個(gè)私有成員變量
/**
* Daemon reference.
*/
private Object catalinaDaemon = null;
它會(huì)在Bootstrap的init()方法中通過(guò)反射的方式完成初始化. 下面我們回過(guò)頭來(lái)看init()方法的源碼.
public void init()
throws Exception
{
// Set Catalina path
setCatalinaHome();
setCatalinaBase();
initClassLoaders();
Thread.currentThread().setContextClassLoader(catalinaLoader);
SecurityClassLoad.securityClassLoad(catalinaLoader);
// Load our startup class and call its process() method
if (log.isDebugEnabled())
log.debug("Loading startup class");
Class> startupClass =
catalinaLoader.loadClass
("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();
// Set the shared extensions class loader
if (log.isDebugEnabled())
log.debug("Setting startup class properties");
String methodName = "setParentClassLoader";
Class> paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
catalinaDaemon = startupInstance;
}
可以看到init()方法創(chuàng)建了一個(gè)Catalina對(duì)象, 并把該對(duì)象賦給了catalinaDaemon.
再回過(guò)頭來(lái)看之前分享給大家的啟動(dòng)流程圖, 對(duì)應(yīng)的是這一塊
后面的過(guò)程我就不逐一分析了, 你可以按照這張圖去跟蹤代碼進(jìn)行驗(yàn)證. 最終所有模塊都能被初始化并啟動(dòng).
本篇結(jié)束
看到這里相信你應(yīng)該對(duì)tomcat的啟動(dòng)過(guò)程已經(jīng)有一個(gè)清晰的認(rèn)識(shí)了, 但是這僅僅是理解tomcat的開始, 下一篇文章開始我將會(huì)詳細(xì)介紹tomcat中的組件, 以及組件間的關(guān)系. 了解了各個(gè)組件后, tomcat的結(jié)構(gòu)于你而言將不再神秘.
擴(kuò)展閱讀:
總結(jié)
以上是生活随笔為你收集整理的java tomcat源码_详解Tomcat系列(一)-从源码分析Tomcat的启动的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux mysql清除缓存_案例:通
- 下一篇: java.lang包含_原因:java.