Tomcat代码学习日记系列. (本贴只接受技术型讨论) | Getting started. 准备工作 决定利用一段时间系统的来研究tomcat源码, 希望大家积极参与. 每周五,我争取把写一篇内读源码的体会. 准备工作: 下载Tomcat528 由于528是一个比较稳定的版本, 我们就从它开始. http://archive.apache.org/dist/jakarta/tomcat-5/v5.0.28/src/jakarta-tomcat-5.0.28-src.zip开始.
下载 eclipse ide www.eclipse.org 配置好eclipse后, 新建一个java工程tomcatcode. 采用src/bin 组织结构. 下载源码的目录下搜索org . 然后把所有得到的文件夹全部copy 到eclispe/workspace/tomcatcode/src/ 目录下, 启动eclipse刷新工程tomcatcode/src目录. 休息一下, 经过很多编译错误后, 记得要导入以下jar包. 搜索tomcat安装目录下, *.jar , 把这些jar包统统导入.tomcatcode工程中.
OK 现在错误已经减少到基本可以接受的程度了, 不会影响我们阅读代码了.
我们将从以下文件开始, %Tomcat_home%/bin下的 startup.bat, startup.sh. 进一步阅读我们还会接触到.该目录下的bootstrap.jar 第一篇日记里, 我们将从org.apache.catalina.startup.Bootstrap 开始 |
| |
天堂在哪里? <script type="text/javascript"> <!-- google_ad_client = 'pub-4196225375348397';google_ad_width = 468;google_ad_height = 60;google_ad_format = '468x60_as';google_ad_channel ='6300525099';google_color_border = 'CCCCCC';google_color_bg = 'FFFFFF';google_color_link = '000000';google_color_url = '666666';google_color_text = '333333';//--> </script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script> name="google_ads_frame" marginwidth="0" marginheight="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-4196225375348397&dt=1114703851652&lmt=1114703851&prev_fmts=728x90_as&format=468x60_as&output=html&channel=6300525099&url=http%3A%2F%2Fwww.matrix.org.cn%2Fforum_view.asp%3Fforum_id%3D27%26view_id%3D17007&color_bg=FFFFFF&color_text=333333&color_link=000000&color_url=666666&color_border=CCCCCC&ref=http%3A%2F%2Fwww.matrix.org.cn%2Fjava.asp&u_h=768&u_w=1024&u_ah=740&u_aw=1024&u_cd=16&u_tz=480&u_java=true" frameborder="0" width="468" scrolling="no" height="60" allowtransparency="65535"> |
|
| Java文栏:ROR历险记 |
|
jinchen | |
| | | 等级: 论坛版主 头衔:不是天使 贴子:59 积分:75 Matrix币:0 注册:2005-2-23 |
|
| 第 2 楼 | |
| Tomcat源码学习日记第一周 startup week1
从startup.bat开始. 找到%TOMCAT_HOME%/bin 目录下的startup.dat文件, 用文本编辑器(notepad, editplus, ultraedit等)打开
@echo off if "%OS%" == "Windows_NT" setlocal rem --------------------------------------------------------------------------- rem Start script for the CATALINA Server rem rem $Id: startup.bat,v 1.6 2004/05/27 18:25:11 yoavs Exp $ 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
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
快速浏览一下, 发现它做了以下事情, 寻找系统环境变量中是否有CATALINA_HOME 如果没有就赋给它当前目录 设置一个执行标签 set EXECUTABLE=%CATALINA_HOME%/bin/catalina.bat 检查bin目录下是否含有catalina.bat 文件, 如果没有给出适当的信息.
...执行bin目录(指tomcat安装目录下bin目录) catalina.bat call "%EXECUTABLE%" start %CMD_LINE_ARGS%
unix/linux 环境下
查看bin目录下startup.sh #!/bin/sh # ----------------------------------------------------------------------------- # Start Script for the CATALINA Server # # $Id: startup.sh,v 1.3 2002/08/04 18:19:43 patrickl Exp $ # -----------------------------------------------------------------------------
# resolve links - $0 may be a softlink PRG="$0"
while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> /(.*/)$'` if expr "$link" : '.*/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fi done PRGDIR=`dirname "$PRG"` EXECUTABLE=catalina.sh
# Check that target executable exists if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then echo "Cannot find $PRGDIR/$EXECUTABLE" echo "This file is needed to run this program" exit 1 fi
exec "$PRGDIR"/"$EXECUTABLE" start "$@"
这是一个unix/linux shell编程脚本. 功能与startup.bat类似, 不过这里做了一个有关文件连接的处理.然后调用 catalina.sh unix/linux 环境以后不再说明比较还要了解一些必要的操作系统相关知识.
查看bin目录下catalina.bat (篇幅有限这里不再给出文件的全部代码,请到相关目录查看)
不要被它唬住了, 其实没什么太困难的东西. 让我们仔细看一下. 顺便说一句,读代码, 不要指望一次把所有的东西都理解,(基本上这不可能,一时不明白的就放放吧.) rem 是批处理命令中 类似注释的意思, 我们把startup.bat 和 catalina.bat 文件第一行 @echo off命令 前面加一个 rem : 改为 rem @echo off (为了理解tomcat启动过程,我们打开echo输出, 现在执行startup.bat 看看dos输出什么了)
运行 cmd , cd d:/tmcat528/bin, startup 我给这些输出加了一些简单的注释, 用/**/ 和// 表示 同c++和java的注释语法 D:/Tomcat528/bin>startup.bat
D:/Tomcat528/bin>rem @echo off //如果是winnt操作系统, 则对这次环境变量的设置只对当前批处理文件有效 D:/Tomcat528/bin>if "Windows_NT" == "Windows_NT" setlocal
D:/Tomcat528/bin>rem ----------------------------------------------------------- ---------------- /* 以下是一些欢迎版本等信息. */ D:/Tomcat528/bin>rem Start script for the CATALINA Server
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem $Id: startup.bat,v 1.6 2004/05/27 18:25:11 yoavs Exp $
D:/Tomcat528/bin>rem ----------------------------------------------------------- ---------------- //判断CATALINA_HOME 是否已经设置 D:/Tomcat528/bin>rem Guess CATALINA_HOME if not defined
D:/Tomcat528/bin>set CURRENT_DIR=D:/Tomcat528/bin
D:/Tomcat528/bin>if not "D:/Tomcat528" == "" goto gotHome
D:/Tomcat528/bin>if exist "D:/Tomcat528/bin/catalina.bat" goto okHome
D:/Tomcat528/bin>set EXECUTABLE=D:/Tomcat528/bin/catalina.bat
D:/Tomcat528/bin>rem Check that target executable exists //设置执行标签 D:/Tomcat528/bin>if exist "D:/Tomcat528/bin/catalina.bat" goto okExec
D:/Tomcat528/bin>rem Get remaining unshifted command line arguments and save the m in the
D:/Tomcat528/bin>set CMD_LINE_ARGS=
D:/Tomcat528/bin>if """" == """" goto doneSetArgs //执行catalina.bat D:/Tomcat528/bin>call "D:/Tomcat528/bin/catalina.bat" start
D:/Tomcat528/bin>rem @echo off
D:/Tomcat528/bin>if "Windows_NT" == "Windows_NT" setlocal
D:/Tomcat528/bin>rem ----------------------------------------------------------- ----------------
D:/Tomcat528/bin>rem Start/Stop Script for the CATALINA Server
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem Environment Variable Prequisites
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem CATALINA_HOME May point at your Catalina "build" directory.
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem CATALINA_BASE (Optional) Base directory for resolving dynamic portions
D:/Tomcat528/bin>rem of a Catalina installation. If not present, resolves to
D:/Tomcat528/bin>rem the same directory that CATALINA_HOME points to.
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem CATALINA_OPTS (Optional) Java runtime options used when the "start",
D:/Tomcat528/bin>rem "stop", or "run" command is executed.
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem CATALINA_TMPDIR (Optional) Directory path location of temporary directory
D:/Tomcat528/bin>rem the JVM should use (java.io.tmpdir). Def aults to
D:/Tomcat528/bin>rem d:/Tomcat528/temp.
D:/Tomcat528/bin>rem //这就是说启动Tomcat要求你必须装好JDK (Java Development Kit)并且设置好 %JAVA_HOME%才能启动 D:/Tomcat528/bin>rem JAVA_HOME Must point at your Java Development Kit installation.
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem JAVA_OPTS (Optional) Java runtime options used when the "start",
D:/Tomcat528/bin>rem "stop", or "run" command is executed.
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem JSSE_HOME (Optional) May point at your Java Secure Sockets Extension //看起来好像是把自定义的jar文件放在这里,系统讲自动装载. D:/Tomcat528/bin>rem (JSSE) installation, whose JAR files will be added to the
D:/Tomcat528/bin>rem system class path used to start Tomcat.
D:/Tomcat528/bin>rem Java 平台调试器体系结构(Java Platform Debugger Architecture,JPDA)看起来像有关调试的一些控制. 我们先不管它 D:/Tomcat528/bin>rem JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start"
D:/Tomcat528/bin>rem command is executed. The default is "dt_shmem".
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start"
D:/Tomcat528/bin>rem command is executed. The default is "jdbconn".
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem $Id: catalina.bat,v 1.9.2.1 2004/08/21 15:49:47 yoavs Exp $
D:/Tomcat528/bin>rem ----------------------------------------------------------- ----------------
D:/Tomcat528/bin>rem Guess CATALINA_HOME if not defined
D:/Tomcat528/bin>set CURRENT_DIR=D:/Tomcat528/bin
D:/Tomcat528/bin>if not "D:/Tomcat528" == "" goto gotHome
D:/Tomcat528/bin>if exist "D:/Tomcat528/bin/catalina.bat" goto okHome
D:/Tomcat528/bin>rem Get standard environment variables
D:/Tomcat528/bin>if exist "D:/Tomcat528/bin/setenv.bat" call "D:/Tomcat528/bin/s etenv.bat"
D:/Tomcat528/bin>rem Get standard Java environment variables
D:/Tomcat528/bin>if exist "D:/Tomcat528/bin/setclasspath.bat" goto okSetclasspat h
D:/Tomcat528/bin>set BASEDIR=D:/Tomcat528 //这里设置环境变量classpath 调用classpath.bat D:/Tomcat528/bin>call "D:/Tomcat528/bin/setclasspath.bat"
D:/Tomcat528/bin>rem ----------------------------------------------------------- ----------------
D:/Tomcat528/bin>rem Set CLASSPATH and Java options
D:/Tomcat528/bin>rem
D:/Tomcat528/bin>rem $Id: setclasspath.bat,v 1.6.2.1 2004/08/21 15:49:50 yoavs E xp $
D:/Tomcat528/bin>rem ----------------------------------------------------------- ----------------
D:/Tomcat528/bin>rem Make sure prerequisite environment variables are set
D:/Tomcat528/bin>if not "D:/j2sdk1.4.2_06" == "" goto gotJavaHome
D:/Tomcat528/bin>if not exist "D:/j2sdk1.4.2_06/bin/java.exe" goto noJavaHome
D:/Tomcat528/bin>if not exist "D:/j2sdk1.4.2_06/bin/javaw.exe" goto noJavaHome
D:/Tomcat528/bin>if not exist "D:/j2sdk1.4.2_06/bin/jdb.exe" goto noJavaHome
D:/Tomcat528/bin>if not exist "D:/j2sdk1.4.2_06/bin/javac.exe" goto noJavaHome
D:/Tomcat528/bin>goto okJavaHome
D:/Tomcat528/bin>if not "D:/Tomcat528" == "" goto gotBasedir
D:/Tomcat528/bin>if exist "D:/Tomcat528/bin/setclasspath.bat" goto okBasedir
D:/Tomcat528/bin>rem Set the default -Djava.endorsed.dirs argument
D:/Tomcat528/bin>set JAVA_ENDORSED_DIRS=D:/Tomcat528/common/endorsed
D:/Tomcat528/bin>rem Set standard CLASSPATH
D:/Tomcat528/bin>rem Note that there are no quotes as we do not want to introduc e random
D:/Tomcat528/bin>rem quotes into the CLASSPATH
D:/Tomcat528/bin>set CLASSPATH=D:/j2sdk1.4.2_06/lib/tools.jar
D:/Tomcat528/bin>rem Set standard command for invoking Java.
D:/Tomcat528/bin>rem Note that NT requires a window name argument when using sta rt.
D:/Tomcat528/bin>rem Also note the quoting as JAVA_HOME may contain spaces.
D:/Tomcat528/bin>set _RUNJAVA="D:/j2sdk1.4.2_06/bin/java"
D:/Tomcat528/bin>set _RUNJAVAW="D:/j2sdk1.4.2_06/bin/javaw"
D:/Tomcat528/bin>set _RUNJDB="D:/j2sdk1.4.2_06/bin/jdb"
D:/Tomcat528/bin>set _RUNJAVAC="D:/j2sdk1.4.2_06/bin/javac"
D:/Tomcat528/bin>goto end
D:/Tomcat528/bin>rem Add on extra jar files to CLASSPATH
D:/Tomcat528/bin>if "" == "" goto noJsse
D:/Tomcat528/bin>set CLASSPATH=D:/j2sdk1.4.2_06/lib/tools.jar;D:/Tomcat528/bin/b ootstrap.jar
D:/Tomcat528/bin>if not "d:/Tomcat528" == "" goto gotBase
D:/Tomcat528/bin>if not "" == "" goto gotTmpdir
D:/Tomcat528/bin>set CATALINA_TMPDIR=d:/Tomcat528/temp
D:/Tomcat528/bin>rem ----- Execute The Requested Command ----------------------- ----------------
D:/Tomcat528/bin>echo Using CATALINA_BASE: d:/Tomcat528 Using CATALINA_BASE: d:/Tomcat528
D:/Tomcat528/bin>echo Using CATALINA_HOME: D:/Tomcat528 Using CATALINA_HOME: D:/Tomcat528
D:/Tomcat528/bin>echo Using CATALINA_TMPDIR: d:/Tomcat528/temp Using CATALINA_TMPDIR: d:/Tomcat528/temp
D:/Tomcat528/bin>echo Using JAVA_HOME: D:/j2sdk1.4.2_06 Using JAVA_HOME: D:/j2sdk1.4.2_06
D:/Tomcat528/bin>set _EXECJAVA="D:/j2sdk1.4.2_06/bin/java" //这里是程序的入口类马上就会关心它 D:/Tomcat528/bin>set MAINCLASS=org.apache.catalina.startup.Bootstrap
D:/Tomcat528/bin>set ACTION=start
D:/Tomcat528/bin>set SECURITY_POLICY_FILE=
D:/Tomcat528/bin>set DEBUG_OPTS=
D:/Tomcat528/bin>set JPDA=
D:/Tomcat528/bin>if not ""start"" == ""jpda"" goto noJpda
D:/Tomcat528/bin>if ""start"" == ""debug"" goto doDebug
D:/Tomcat528/bin>if ""start"" == ""run"" goto doRun
D:/Tomcat528/bin>if ""start"" == ""start"" goto doStart
D:/Tomcat528/bin>shift
D:/Tomcat528/bin>if not "Windows_NT" == "Windows_NT" goto noTitle
D:/Tomcat528/bin>set _EXECJAVA=start "Tomcat" "D:/j2sdk1.4.2_06/bin/java"
D:/Tomcat528/bin>goto gotTitle
D:/Tomcat528/bin>if not """" == ""-security"" goto execCmd
D:/Tomcat528/bin>rem Get remaining unshifted command line arguments and save the m in the
D:/Tomcat528/bin>set CMD_LINE_ARGS=
D:/Tomcat528/bin>if """" == """" goto doneSetArgs
D:/Tomcat528/bin>rem Execute Java with the applicable properties
D:/Tomcat528/bin>if not "" == "" goto doJpda
D:/Tomcat528/bin>if not "" == "" goto doSecurity 执行java 命令带一些比较多的参数选项. D:/Tomcat528/bin>start "Tomcat" "D:/j2sdk1.4.2_06/bin/java" -Djava.endorsed.d irs="D:/Tomcat528/common/endorsed" -classpath "D:/j2sdk1.4.2_06/lib/tools.jar;D: /Tomcat528/bin/bootstrap.jar" -Dcatalina.base="d:/Tomcat528" -Dcatalina.home="D: /Tomcat528" -Djava.io.tmpdir="d:/Tomcat528/temp" org.apache.catalina.startup.Boo tstrap start
D:/Tomcat528/bin>goto end D:/Tomcat528/bin>
此时Tomcat已经启动 我们关心catalina.bat 做的关键动作. call "%CATALINA_HOME%/bin/setclasspath.bat" //设置classpath set SECURITY_POLICY_FILE=%CATALINA_BASE%/conf/catalina.policy //指定安全策略管理文件
/* * 指定程序入口类. */ set _EXECJAVA=%_RUNJAVA% set MAINCLASS=org.apache.catalina.startup.Bootstrap set ACTION=start set SECURITY_POLICY_FILE= set DEBUG_OPTS= set JPDA=
/* * 启动应用带设置好的各种参数 */ %_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%
首先找到org.apache.catalina.startup 包下的Bootstrap文件。 先看main() 推进进行调试如此可以对程序流程有一个清晰的认识。
/** * Main method, used for testing only. * * @param args Command line arguments to be processed */ public static void main(String args[]) {
/** * 加载JMX,我们先不理它:) */ try { // Attempt to load JMX class new ObjectName("test:foo=bar"); } catch (Throwable t) { System.out.println(JMX_ERROR_MESSAGE); try { // Give users some time to read the message before exiting Thread.sleep(5000); } catch (Exception ex) { } return; } /* * /** * Daemon object used by main. * 该类声明了一个静态对象引用。 * private static Bootstrap daemon = null; */ if (daemon == null) { daemon = new Bootstrap(); try { daemon.init(); } catch (Throwable t) { t.printStackTrace(); return; } }
try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; }
if (command.equals("startd")) { args[0] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[0] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args); daemon.start(); } else if (command.equals("stop")) { daemon.stopServer(args); } } catch (Throwable t) { t.printStackTrace(); }
} 查看init()方法 首先调用以下3个方法 // Set Catalina path 设置catalina.home setCatalinaHome(); //设置 setCatalinaBase setCatalinaBase(); //建立3个ClassLoader initClassLoaders(); { commonLoader = createClassLoader("common", null); catalinaLoader = createClassLoader("server", commonLoader); sharedLoader = createClassLoader("shared", commonLoader); }
什么是classLoader 查看javadoc 以下是1.4javadoc 的简介. public abstract class ClassLoader extends Object A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system. 现在,应用程序已经加载了需要的基本classes jar包等。从一个配置文件catalina.home/conf/catalina.properties读取 这是一种通用的技术,把需要的资源中固化的文件中读出来文件格式比较早的有*.ini unix/linux下的 *.profile 以及java常用的*.properties. 和现在非常流行的 *.xml 等。如此我们可以把可能变化比较大的参数保存在 配置文件中, 程序通过特定的api 读取。如数据库连接参数等。 不再多说这是一种常见而实用的技术。 有兴趣可以看一下hibernate加载数据库连接的源码, struts, spring等初始化代码。 加载的文件 common.loader=${catalina.home}/common/classes,${catalina.home}/common/endorsed/*.jar,${catalina.home}/common/lib/*.jar server.loader=${catalina.home}/server/classes,${catalina.home}/server/lib/*.jar shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar 接下来init()执行了以下语句 Class startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance();
// Set the shared extensions class loader if (debug >= 1) log("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; 现在你需要看一下java的反射机制, 否则很难读懂这部分代码, 简单的说java的反射技术提供 了一种类的自检[c++中可没有这种技术:)] 它能给出这个类的几乎全部信息如数据成员,方法的参数列表 返回类型等。 //创建了一个Catalina对象. Object startupInstance = startupClass.newInstance(); // 相当于调用 startupInstance.setParentClassLoader(java.lang.ClassLoader); method.invoke(startupInstance, paramvalues); 注意tomcat5.0.2.8 的启动代码与tomcat4.x.x.x 有所区别。 4.x版本这时直接调用了startupInstance.process()方法。而这里还有一些其他处理。 由于我们没有输入命令行参数。 直接startup.... 程序进入 else if (command.equals("start")) { //运用反射相当于上调用了catalinaDaemon.setAwait(true); daemon.setAwait(true); //运用反射相当于上调用了catalinaDaemon.load("start"); daemon.load(args); //运用反射相当于上调用了catalinaDaemon.start(); daemon.start(); 到这里不能不提一下Catalina的 public void load() 方法 public void load() { //设置目录 initDirs();
// Before digester - it may be needed //看了一眼不大清楚什么意思,放一放 // 心急的人可以去查一下文档 基本上是说tomcat作为嵌入式应用的时候使用 // http://jakarta.apache.org/tomcat/tomcat-5.5-doc/catalina/docs/api/org/apache/catalina/startup/Embedded.html initNaming();
// Create and execute our Digester
Digester digester = createStartDigester(); //记录时间, 还记得Tomcat启动后显示一个 用了多少ms 时间吧. 例 信息: Server startup in 19337 ms long t1 = System.currentTimeMillis();
Exception ex = null; InputSource inputSource = null; InputStream inputStream = null; try { File file = configFile(); inputStream = new FileInputStream(file); inputSource = new InputSource("file&://" + file.getAbsolutePath()); } catch (Exception e) { ; } if (inputStream == null) { try { inputStream = getClass().getClassLoader() .getResourceAsStream(getConfigFile()); inputSource = new InputSource (getClass().getClassLoader() .getResource(getConfigFile()).toString()); } catch (Exception e) { ; } }
if (inputStream == null) { System.out.println("Can't load server.xml"); return; }
try { inputSource.setByteStream(inputStream); digester.push(this); digester.parse(inputSource); inputStream.close(); } catch (Exception e) { System.out.println("Catalina.start using " + getConfigFile() + ": " + e); e.printStackTrace(System.out); return; }
// Replace System.out and System.err with a custom PrintStream // TODO: move to Embedded, make it configurable SystemLogHandler systemlog = new SystemLogHandler(System.out); System.setOut(systemlog); System.setErr(systemlog);
// Start the new server if (server instanceof Lifecycle) { try { server.initialize(); } catch (LifecycleException e) { log.error("Catalina.start", e); } }
long t2 = System.currentTimeMillis(); log.info("Initialization processed in " + (t2 - t1) + " ms");
}
/* * 我不喜欢提太多的设计模式, 我们作为一种使用方案的思路来理解就可以了。 * Digester模式参考 http://www.uml.org.cn/rjjg/rjjg28.htm * * createStartDigester()方法创建了装载Tomcat核心组件资源规则。我们现在需要知道Tomcat5.x采用的是面向 * 组件的软件技术,似乎它是比面向对象更加深奥,不过没什么神秘的, 如果你们工科出身你大可以理解为 * 一个系统,比如一个车床,如很多系统组成,如动力系统,控制系统,物料循环系统,每个系统根据约定的 * 工程标准负责自己的工作,并且每个零件系统可以由不同的厂家生产。 如果软件工程能达到这种程度当然是 * 几乎完美的,遗憾的是软件产业还是一门新兴产业,它要学习其他工业的地方还很多。从技术和经验上都还有很多 * 欠缺,不过面向组件的编程技术,毫无疑问是一个值得我们研究的方面。(忍不住说了点废话--_--) * * 让我们看看这一大堆代码干了些什么。这里用到了规则集打包技术。即将相关同类型规则都放在一个类中, * 此由这些规则被装载然后被注册使用。我们大概可以猜到这些怪异的代码似乎创建了以下对象, * 如Server/Service/Engine/Host/Context/ 这就是tomcat的核心组件。以后的日记里我们将逐个介绍。 * */ 我们看一下Digester解析的文件。conf目录下的server.xml 现在我们明白了刚才发生了什么.根据server.xml文件,程序已经加载了server.xml定义的所有对象, 并且已经把程序里定义的相关类的属性值赋值给创建的对象。 例如:<Server port="8005" shutdown="SHUTDOWN" debug="0"> 结果创建了一个类型为 org.apache.catalina.core.StandardServer的对象,属性port=8005 shutdown="SHUTDOWN" debug=0 不可思议, 确实不错,感叹一下,汗。。。。。。。。:) 经过了无数次检查,,读取配置文件的操作后,我们终于加载了应用程序需要的资源,同时执行了这些对象 需要进行的初始化方法。 终于执行到了start() /** * Start a new server instance. */ public void start() {
if (server == null) { load(); }
long t1 = System.currentTimeMillis();
// Start the new server if (server instanceof Lifecycle) { try { ((Lifecycle) server).start(); } catch (LifecycleException e) { log.error("Catalina.start: ", e); } }
long t2 = System.currentTimeMillis(); log.info("Server startup in " + (t2 - t1) + " ms");
try { //创建一个钩子,当输入shutdown时关闭应用程序。 // Register shutdown hook if (useShutdownHook) { if (shutdownHook == null) { shutdownHook = new CatalinaShutdownHook(); } Runtime.getRuntime().addShutdownHook(shutdownHook); } } catch (Throwable t) { // This will fail on JDK 1.2. Ignoring, as Tomcat can run // fine without the shutdown hook. }
if (await) { await(); stop(); }
} 我看到了一个LIfecycle接口,估计是管理生命周期的,毫无疑问非常重要, 这里调用了 org.apache.catalina.core.StandardServer 的start()方法。 该方法循环调用了, 所有services[i]对象的start()方法。 接着调用了org.apache.catalina.core.StandardServiece的start方法 if (container != null) { synchronized (container) { if (container instanceof Lifecycle) { ((Lifecycle) container).start(); } } } //依次调用了一个或多个Server/Service/Engine/Host/Context/对象的start().....应用程序启动完毕。 ok 写到这里,我觉得有点累了, 粗略的读了一下tomcat启动相关代码。 只能说知其然,而不知其 所以然。但是程序的思路清晰而明确,将复杂的应用规划的井井有条。 不能不说是一个优秀的设计。 总结一下, 我们大概知道了再我们输入startup后发生什么事情, 对tomcat启动过程有了一个感性的认识。 估计,我们大家都承认一本好书, 读一遍是远远不够的,同样代码也需要读个2-3次吧 这里分析的只是写代码的皮毛耳, 要想体会到程序设计思路, 我们还需要相当大的努力, 不过无论如何,我们已经走出了第一步。 由于个人水平有限,几乎难免有不当甚至错误之处。请大家谅解。 抛砖引玉,期待大家的精彩文章。 Looking forwards: 下一篇里,将对org.apache.catalina.core包的一些类做一定的介绍。 同时, 我们需要补充一些servlet技术框架. http协议的相关知识。 see u guys next week ! Good luck! by jinchen 2005-3-4 |
|
|