日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java tomcat源码_详解Tomcat系列(一)-从源码分析Tomcat的启动

發(fā)布時(shí)間:2024/10/12 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java tomcat源码_详解Tomcat系列(一)-从源码分析Tomcat的启动 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在整個(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)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。