- 浏览: 22155 次
- 性别:
- 来自: 深圳
最新评论
本文从源代码入手,分析Tomcat的启动过程,共两篇文章。这是第一篇。
main方法
第一阶段
第二阶段
第三阶段
启动参数的区别
一个Bug
configtest启动参数
一般,我们直接运行startup.sh 来 启动Tomcat 。最终执行的命令是:
view sourceprint?1 java [options] org.apache.catalina.startup.Bootstrap start
options是JVM启动参数,这里忽略。
main方法
可见,Tomcat 的启动类是org.apache.catalina.startup.Bootstrap , 启动参数是start 。我们从该类的main 方法看起。
view sourceprint?01 public static void main(String args[]) {
02 try {
03
// Attempt to load JMX class
04 new ObjectName("test:foo=bar");
05 } catch (Throwable t) {
06 System.out.println(JMX_ERROR_MESSAGE);
07 try {
08
// Give users some time to read the message before exiting
09 Thread.sleep(5000);
10 } catch (Exception ex) {
11 }
12 return;
13 }
14
15 if (daemon == null) {
16 daemon = new Bootstrap();
17 try {
18 daemon.init();
19 } catch (Throwable t) {
20 t.printStackTrace();
21 return;
22 }
23 }
24
25 try {
26 String command = "start";
27 if (args.length > 0) {
28 command = args[args.length - 1];
29 }
30 if (command.equals("startd")) {
31 args[0] = "start";
32 daemon.load(args);
33 daemon.start();
34 } else if (command.equals("stopd")) {
35 args[0] = "stop";
36 daemon.stop();
37 } else if (command.equals("start")) {
38 daemon.setAwait(true);
39 daemon.load(args);
40 daemon.start();
41 } else if (command.equals("stop")) {
42 daemon.stopServer(args);
43 } else {
44 log.warn("Bootstrap: command \"" + command + "\" does not exist.");
45 }
46 } catch (Throwable t) {
47 t.printStackTrace();
48 }
49 }
上述代码主要分为三段:
第一段是检查JMX 支持
第二段创建Boostrap 实 例并初始化
第三段根据启动参数,执行进一步操作
第一阶段
乍一看,第一段似乎可有可无。它只是创 建了一个不被使用的ObjectName 对象,如果创建失败,就打印一条错误信息。而 且在Tomcat 6 中,已经移除了这段代码。
view sourceprint?01 try {
02
// Attempt to load JMX class
03 new ObjectName("test:foo=bar");
04 } catch (Throwable t) {
05 System.out.println(JMX_ERROR_MESSAGE);
06 try {
07
// Give users some time to read the message before exiting
08 Thread.sleep(5000);
09 } catch (Exception ex) {
10 }
11 return;
12 }
这段代码的作用是什么呢?这其实和J2SE 1.4 的兼容性有关。Tomcat 5 使用JMX 作为管理和监控机制,但是J2SE 1.4 本身并不支持JMX ,像ObjectName 这些JMX 类 并不包括J2SE 1.4 的API 中。因此,Tomcat 5 不能直接运行 在J2SE 1.4 及之前版本上。
但是Tomcat 5 的设计目标是支持运行在J2SE 1.4 上的。因此,要达到这个目标,Tomcat 5 须 将JMX 类作为兼容包(compatibility package )额外添加到Tomcat 启动类路径中。
我 们有两种方法获得兼容包:
从Tomcat 的官方下载 页面下载兼容包,参见http://tomcat.apache.org/download-55.cgi
从Tomcat 的源代码构建兼容包,参见http://jarfield.iteye.com/blog/604198
不 管怎样,Tomcat 5 不能保证用户安装了兼容包,因此在启动时,它首先检 查能够加载ObjectName 类,以此判断兼容包是否安装。如果没有安装,则向标准 输出打印一条错误信息:
This release of Apache Tomcat was packaged to run on J2SE 5.0 or later. It can be run on earlier JVMs by downloading and installing a compatibility package from the Apache Tomcat binary download page.
这 条信息也就是第一段代码中JMX_ERROR_MESSAGE 变量的值。下面是Bootstrap 类声明该变量的代码:
private static final String JMX_ERROR_MESSAGE =
"This release of Apache Tomcat was packaged to run on J2SE 5.0 \n"
+ "or later. It can be run on earlier JVMs by downloading and \n"
+ "installing a compatibility package from the Apache Tomcat \n"
+ "binary download page.";
那为什么Tomcat 6中移除了第一段代码,不检查兼容包是否安装了呢?原因很简单,Tomcat 6的设计目标并不包括J2SE 1.4及之前版本。
OK ,看完了第一段,我们进入正题,看看第二段代码。
第二阶段
view sourceprint?1 if (daemon == null) {
2 daemon = new Bootstrap();
3 try {
4 daemon.init();
5 } catch (Throwable t) {
6 t.printStackTrace();
7 return;
8 }
9 }
可见,这段代码的主要逻辑在Bootstrap 的init 方法。该方法的工作包括:
设 置Catalina (Tomcat Servlet 容器的代号)的路径:CATALINA_HOME 和CATALINA_BASE
初始化Tomcat 的类加载器体系
创建org.apache.catalina.startup.Catalina 对 象(启动阶段剩余的工作由Catalina类 完成)
为了节省篇幅,init 方法的代码另文表述 。下面我们看看第三段代码。
第三阶段
view sourceprint?01 try {
02 String command = "start";
03 if (args.length > 0) {
04 command = args[args.length - 1];
05 }
06 if (command.equals("startd")) {
07 args[0] = "start";
08 daemon.load(args);
09 daemon.start();
10 } else if (command.equals("stopd")) {
11 args[0] = "stop";
12 daemon.stop();
13 } else if (command.equals("start")) {
14 daemon.setAwait(true);
15 daemon.load(args);
16 daemon.start();
17 } else if (command.equals("stop")) {
18 daemon.stopServer(args);
19 } else {
20 log.warn("Bootstrap: command \"" + command + "\" does not exist.");
21 }
22 } catch (Throwable t) {
23 t.printStackTrace();
24 }
容 易看出,这段代码的主要逻辑就是根据不同的启动参数,执行不同的工作。可以接受的启动参数包括4 种:startd stopd start stop 。
启动参数决定了启动还是停止Tomcat 。如何启动,如何停止,另文表述 。本文问想讨论的问题是:除了start 和stop ,为什么 还有startd 和stopd ? 它们有什么区别呢?
启动参数的区别
我们先看看start 和startd 。处理start 的 代码比startd 仅多了一行:
daemon.setAwait(true);
这行代码执行后,主线程(即main 函数所在的线程)在Tomcat 启 动过程结束时并不会退出,而是监听SHUTDOWN 端口(默认端口是8005 )。该端口如果接收SHUTDOWN 命 令,就停止Tomcat ;如果收到的是其他命令,则忽略,继续监听。这样,我 们就可以在Tomcat 进程之外通过网络停止Tomcat 。
如果以startd 参 数启动Tomcat ,主线程会在启动结束时退出,只剩下主线程创建的其他线程 (HTTP 监听线程、HTTP 请求线程、Tomcat 后台线程等)。 这样,我们并不能通过网络停止Tomcat 。
如果启动参数是stop ,那么将调用Bootstrap类 的stopServer 方法。该方法通过SHUTDOWN 端口向Tomcat 发送SHUTDOWN 命 令,从而停止Tomcat 。shutdown.bat 就是通过这种方式关闭Tomcat , 它最终执行的命令是:
java [options] org.apache.catalina.startup.Bootstrap stop
如果启动参数是stopd,那么 Bootstrap将直接调用Catalina的stop方法,直接停止Tomcat。
综上所述,以start 启动,就以stop 停 止;以startd 启动,就以stopd 停 止。
如果将Tomcat 作为独立的进程运行,那么应该使用start 和stop ,这样 我们就可以通过网络停止Tomcat 。
如果将Tomcat 以嵌入到应用进程的方式运行(例如Eclipse 中运行Tomcat ), 那么应该使用startd 和stopd 。 这样,宿主程序通过普通的方法调用,来启动和停止Tomcat 。
一个Bug
关于这4 个启动参数的讨论,可以参见Bug 47881 。这个Bug 的本意是要指出第三段代码的一个问题 ,不过恰好讨论了各种启动参数的区别。
至于这个Bug ,也比较明显:
args[0] = “start”; 应该是 args[args.length - 1 ] = “start”;
args[0] = “stop”; 应该是 args[args.length - 1 ] = “stop”;
这 个Bug 已经在Tomcat 6 中解决了。
Tomcat 7中引入的configtest启动参数
在Tomcat 7中,新增了configtest启动参数。
view sourceprint?01 public static void main(String args[]) {
02
// 省略部分代码
03 if (command.equals("startd")) {
04 args[args.length - 1] = "start";
05 daemon.load(args);
06 daemon.start();
07
// 省略部分代码
08 } else if (command.equals("configtest")) {
09 daemon.load(args);
10 if (null==daemon.getServer()) {
11 System.exit(1);
12 }
13 System.exit(0);
14 } else {
15
// 省略部分代码
16 }
17 }
顾名思义,configtest是为了检测配置参数是否正确,配置参数的主要来源就是conf/server.xml。
从代码可以看出,configtest启动参数就是把load方法给执行了一遍,然后无条件退出。load方法的代码,另文表述 。这里只要知道,load的主要工作之一就是解析conf/server.xml,从而起到检测配置参数是否正确的作用。
configtest通过exit status来返回检测结果。1表示检测到错误,0表示检测结果正确。如果load方法执行成功,就会创建server实例,通过 daemon.getServer方法返回;反之,如果配置参数不正确,load方法执行失败,那么就不创建server实 例,deamon.getServer方法就返回null。
main方法
第一阶段
第二阶段
第三阶段
启动参数的区别
一个Bug
configtest启动参数
一般,我们直接运行startup.sh 来 启动Tomcat 。最终执行的命令是:
view sourceprint?1 java [options] org.apache.catalina.startup.Bootstrap start
options是JVM启动参数,这里忽略。
main方法
可见,Tomcat 的启动类是org.apache.catalina.startup.Bootstrap , 启动参数是start 。我们从该类的main 方法看起。
view sourceprint?01 public static void main(String args[]) {
02 try {
03
// Attempt to load JMX class
04 new ObjectName("test:foo=bar");
05 } catch (Throwable t) {
06 System.out.println(JMX_ERROR_MESSAGE);
07 try {
08
// Give users some time to read the message before exiting
09 Thread.sleep(5000);
10 } catch (Exception ex) {
11 }
12 return;
13 }
14
15 if (daemon == null) {
16 daemon = new Bootstrap();
17 try {
18 daemon.init();
19 } catch (Throwable t) {
20 t.printStackTrace();
21 return;
22 }
23 }
24
25 try {
26 String command = "start";
27 if (args.length > 0) {
28 command = args[args.length - 1];
29 }
30 if (command.equals("startd")) {
31 args[0] = "start";
32 daemon.load(args);
33 daemon.start();
34 } else if (command.equals("stopd")) {
35 args[0] = "stop";
36 daemon.stop();
37 } else if (command.equals("start")) {
38 daemon.setAwait(true);
39 daemon.load(args);
40 daemon.start();
41 } else if (command.equals("stop")) {
42 daemon.stopServer(args);
43 } else {
44 log.warn("Bootstrap: command \"" + command + "\" does not exist.");
45 }
46 } catch (Throwable t) {
47 t.printStackTrace();
48 }
49 }
上述代码主要分为三段:
第一段是检查JMX 支持
第二段创建Boostrap 实 例并初始化
第三段根据启动参数,执行进一步操作
第一阶段
乍一看,第一段似乎可有可无。它只是创 建了一个不被使用的ObjectName 对象,如果创建失败,就打印一条错误信息。而 且在Tomcat 6 中,已经移除了这段代码。
view sourceprint?01 try {
02
// Attempt to load JMX class
03 new ObjectName("test:foo=bar");
04 } catch (Throwable t) {
05 System.out.println(JMX_ERROR_MESSAGE);
06 try {
07
// Give users some time to read the message before exiting
08 Thread.sleep(5000);
09 } catch (Exception ex) {
10 }
11 return;
12 }
这段代码的作用是什么呢?这其实和J2SE 1.4 的兼容性有关。Tomcat 5 使用JMX 作为管理和监控机制,但是J2SE 1.4 本身并不支持JMX ,像ObjectName 这些JMX 类 并不包括J2SE 1.4 的API 中。因此,Tomcat 5 不能直接运行 在J2SE 1.4 及之前版本上。
但是Tomcat 5 的设计目标是支持运行在J2SE 1.4 上的。因此,要达到这个目标,Tomcat 5 须 将JMX 类作为兼容包(compatibility package )额外添加到Tomcat 启动类路径中。
我 们有两种方法获得兼容包:
从Tomcat 的官方下载 页面下载兼容包,参见http://tomcat.apache.org/download-55.cgi
从Tomcat 的源代码构建兼容包,参见http://jarfield.iteye.com/blog/604198
不 管怎样,Tomcat 5 不能保证用户安装了兼容包,因此在启动时,它首先检 查能够加载ObjectName 类,以此判断兼容包是否安装。如果没有安装,则向标准 输出打印一条错误信息:
This release of Apache Tomcat was packaged to run on J2SE 5.0 or later. It can be run on earlier JVMs by downloading and installing a compatibility package from the Apache Tomcat binary download page.
这 条信息也就是第一段代码中JMX_ERROR_MESSAGE 变量的值。下面是Bootstrap 类声明该变量的代码:
private static final String JMX_ERROR_MESSAGE =
"This release of Apache Tomcat was packaged to run on J2SE 5.0 \n"
+ "or later. It can be run on earlier JVMs by downloading and \n"
+ "installing a compatibility package from the Apache Tomcat \n"
+ "binary download page.";
那为什么Tomcat 6中移除了第一段代码,不检查兼容包是否安装了呢?原因很简单,Tomcat 6的设计目标并不包括J2SE 1.4及之前版本。
OK ,看完了第一段,我们进入正题,看看第二段代码。
第二阶段
view sourceprint?1 if (daemon == null) {
2 daemon = new Bootstrap();
3 try {
4 daemon.init();
5 } catch (Throwable t) {
6 t.printStackTrace();
7 return;
8 }
9 }
可见,这段代码的主要逻辑在Bootstrap 的init 方法。该方法的工作包括:
设 置Catalina (Tomcat Servlet 容器的代号)的路径:CATALINA_HOME 和CATALINA_BASE
初始化Tomcat 的类加载器体系
创建org.apache.catalina.startup.Catalina 对 象(启动阶段剩余的工作由Catalina类 完成)
为了节省篇幅,init 方法的代码另文表述 。下面我们看看第三段代码。
第三阶段
view sourceprint?01 try {
02 String command = "start";
03 if (args.length > 0) {
04 command = args[args.length - 1];
05 }
06 if (command.equals("startd")) {
07 args[0] = "start";
08 daemon.load(args);
09 daemon.start();
10 } else if (command.equals("stopd")) {
11 args[0] = "stop";
12 daemon.stop();
13 } else if (command.equals("start")) {
14 daemon.setAwait(true);
15 daemon.load(args);
16 daemon.start();
17 } else if (command.equals("stop")) {
18 daemon.stopServer(args);
19 } else {
20 log.warn("Bootstrap: command \"" + command + "\" does not exist.");
21 }
22 } catch (Throwable t) {
23 t.printStackTrace();
24 }
容 易看出,这段代码的主要逻辑就是根据不同的启动参数,执行不同的工作。可以接受的启动参数包括4 种:startd stopd start stop 。
启动参数决定了启动还是停止Tomcat 。如何启动,如何停止,另文表述 。本文问想讨论的问题是:除了start 和stop ,为什么 还有startd 和stopd ? 它们有什么区别呢?
启动参数的区别
我们先看看start 和startd 。处理start 的 代码比startd 仅多了一行:
daemon.setAwait(true);
这行代码执行后,主线程(即main 函数所在的线程)在Tomcat 启 动过程结束时并不会退出,而是监听SHUTDOWN 端口(默认端口是8005 )。该端口如果接收SHUTDOWN 命 令,就停止Tomcat ;如果收到的是其他命令,则忽略,继续监听。这样,我 们就可以在Tomcat 进程之外通过网络停止Tomcat 。
如果以startd 参 数启动Tomcat ,主线程会在启动结束时退出,只剩下主线程创建的其他线程 (HTTP 监听线程、HTTP 请求线程、Tomcat 后台线程等)。 这样,我们并不能通过网络停止Tomcat 。
如果启动参数是stop ,那么将调用Bootstrap类 的stopServer 方法。该方法通过SHUTDOWN 端口向Tomcat 发送SHUTDOWN 命 令,从而停止Tomcat 。shutdown.bat 就是通过这种方式关闭Tomcat , 它最终执行的命令是:
java [options] org.apache.catalina.startup.Bootstrap stop
如果启动参数是stopd,那么 Bootstrap将直接调用Catalina的stop方法,直接停止Tomcat。
综上所述,以start 启动,就以stop 停 止;以startd 启动,就以stopd 停 止。
如果将Tomcat 作为独立的进程运行,那么应该使用start 和stop ,这样 我们就可以通过网络停止Tomcat 。
如果将Tomcat 以嵌入到应用进程的方式运行(例如Eclipse 中运行Tomcat ), 那么应该使用startd 和stopd 。 这样,宿主程序通过普通的方法调用,来启动和停止Tomcat 。
一个Bug
关于这4 个启动参数的讨论,可以参见Bug 47881 。这个Bug 的本意是要指出第三段代码的一个问题 ,不过恰好讨论了各种启动参数的区别。
至于这个Bug ,也比较明显:
args[0] = “start”; 应该是 args[args.length - 1 ] = “start”;
args[0] = “stop”; 应该是 args[args.length - 1 ] = “stop”;
这 个Bug 已经在Tomcat 6 中解决了。
Tomcat 7中引入的configtest启动参数
在Tomcat 7中,新增了configtest启动参数。
view sourceprint?01 public static void main(String args[]) {
02
// 省略部分代码
03 if (command.equals("startd")) {
04 args[args.length - 1] = "start";
05 daemon.load(args);
06 daemon.start();
07
// 省略部分代码
08 } else if (command.equals("configtest")) {
09 daemon.load(args);
10 if (null==daemon.getServer()) {
11 System.exit(1);
12 }
13 System.exit(0);
14 } else {
15
// 省略部分代码
16 }
17 }
顾名思义,configtest是为了检测配置参数是否正确,配置参数的主要来源就是conf/server.xml。
从代码可以看出,configtest启动参数就是把load方法给执行了一遍,然后无条件退出。load方法的代码,另文表述 。这里只要知道,load的主要工作之一就是解析conf/server.xml,从而起到检测配置参数是否正确的作用。
configtest通过exit status来返回检测结果。1表示检测到错误,0表示检测结果正确。如果load方法执行成功,就会创建server实例,通过 daemon.getServer方法返回;反之,如果配置参数不正确,load方法执行失败,那么就不创建server实 例,deamon.getServer方法就返回null。
发表评论
-
公钥,私钥和数字签名理解
2013-07-28 11:00 942一、公钥加密 假设一下,我找了两个数字,一个是1,一个是2。 ... -
如何修改weblogic的登录用户名和密码
2012-02-25 11:26 0在XP系统上安装了weblogic server 8.1,安装 ... -
谈下sturts1和struts2的action 线程安全问题
2012-02-23 15:26 1518问及struts方面的内容:aciton是否thread sa ... -
Spring 声明式事务,Propagation属性列表
2012-02-20 15:27 0bean的事物配置: <bean id="b ... -
谈谈java的多线程
2012-02-20 15:06 1310程序、进程和线程: 程序是一段静态的代码,它是应用程序执行的 ... -
servlet 概要和相关技术总结
2011-10-20 15:59 1366view plainprint? servlet文档: ... -
oracle经典sql面试
2011-09-02 22:42 1677一个学校表,school,列class 班级,name ... -
struts2基本原理
2011-09-02 22:14 1121Struts 2 的整体结构可以参考官方结构,在此省略。基本原 ... -
多线程thread,runnalble区别和联系
2011-08-13 11:22 6398[/b] 前端时间碰到了单例模式的问题,涉及到多线程的问题 ... -
MySQL索引类型一览 让MySQL高效运行
2011-03-19 11:34 999索引是快速搜索的关键 ...
相关推荐
Apache Tomcat 5.5.26 是一个广泛使用的开源软件,它是一个符合Java Servlet和JavaServer Pages(JSP)规范的应用服务器,主要用于部署和运行Java Web应用程序。Tomcat是Apache软件基金会Jakarta项目的一部分,它以...
标题中的"apache-tomcat-5.5.26.rar"指的是Apache Tomcat的5.5.26版本,这是一个历史版本,发布于2008年,适用于那些需要旧版本兼容性的项目。这个版本的Tomcat以其轻量级、高效和易于部署的特点而受到开发者欢迎。 ...
这个"apache-tomcat-5.5.26 免安装"版本是专为那些不想进行复杂安装过程的用户设计的,只需解压缩即可立即使用。 Tomcat 5.5.26 是该服务器的一个特定版本,发布于2008年,是Tomcat 5.x系列中的一个稳定版本。在这...
Apache Tomcat 5.5.26 是一个广泛使用的开源软件,它是一个符合Java Servlet和JavaServer Pages(JSP)规范的应用服务器,主要用于部署和运行Java Web应用程序。这个版本的Tomcat是在Java EE 5标准下开发的,因此它...
这个压缩包"apache-tomcat-5.5.26+apache-tomcat-5.5.26-admin.zip"包含了Tomcat服务器的5.5.26版本以及它的管理模块,让我们深入了解一下这两个关键组件。 1. **Tomcat 5.5.26**: 这是Apache Tomcat的一个较早版本...
Tomcat 5.5.26是一款历史悠久且广受欢迎的开源Web应用程序服务器,由Apache软件基金会的Jakarta项目开发。它主要用于部署和运行Java Servlets和JavaServer Pages (JSP)。Tomcat是Java EE(企业版)的一部分,尽管它...
对于开发者来说,研究这些源码可以帮助理解Tomcat的工作流程,解决实际开发中遇到的问题,或者创建符合特定需求的定制化Tomcat版本。不过,由于Tomcat 5.5.26相对较旧,可能不支持最新的Java和Web技术,因此在实际...
标题“tomcat5.5.26.zip”指的是Apache Tomcat服务器的一个特定版本,5.5.26。Tomcat是一款流行的开源Java Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)技术,用于部署和运行Java Web应用程序。这个...
### RHEL5 + Apache2.2.6 + Tomcat5.5.26 整合:构建高效Web服务器环境 #### 第一部分:安装与配置Apache2.2.6 Apache作为全球广泛使用的Web服务器软件之一,其稳定性与性能备受好评。在本教程中,我们将学习如何...
在本教程中,我们将深入探讨如何使用JK插件配置Tomcat 5.5.26与Apache 2.2.9进行集成。JK插件,全称“mod_jk”,是Apache HTTP服务器的一个模块,用于将HTTP请求转发到Tomcat应用服务器,实现两者之间的负载均衡和高...
用于解决使用 Tomcat 5.5.26 Administration Tool 的 Delete Existing Hosts 功能时发生 HTTP Status 500 错误,详见 http://blog.csdn.net/LaoBai_2006/archive/2008/08/28/2844042.aspx。 md5: f8ad905990a96f...
《深入理解Tomcat 5.5.26》 Tomcat 5.5.26是Apache软件基金会的Java Servlet和JavaServer Pages(JSP)容器,它作为开源的Web服务器,广泛应用于各种规模的企业级应用。这个版本的Tomcat以其稳定性、高效性和易于...
Apache Tomcat 5.5.26 是一个广泛使用的开源软件,它是一个符合Java Servlet和JavaServer Pages(JSP)规范的应用服务器,主要用于部署和运行Java Web应用程序。Tomcat是Apache软件基金会Jakarta项目的一部分,以其...
假设tomcat的安装目录为:D:\apache-tomcat-5.5.26 解压Administration Web Application,假设目录为F:\ apache-tomcat-5.5.26 把F:\ apache-tomcat-5.5.25 \server\webapps下面的admin文件夹copy到D:\apache-tomcat...
apache-tomcat-5.5.26Windows Service Installer.EXE ,直接安装并运行即可