`
jarfield
  • 浏览: 202649 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Tomcat 5.5.26源代码分析——启动过程(一)

阅读更多
    1. main方法
      1. 第一阶段
      2. 第二阶段
      3. 第三阶段
    2. 启动参数的区别
    3. 一个Bug
    4. configtest启动参数

    一般,我们直接运行startup.sh 来 启动Tomcat 。最终执行的命令是:

    java [options] org.apache.catalina.startup.Bootstrap start 

    options是JVM启动参数,这里忽略。

     

    main方法

    可见,Tomcat 的启动类是org.apache.catalina.startup.Bootstrap , 启动参数是start 。我们从该类的main 方法看起。

    public static void main(String args[]) {
    
        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;
        }
    
        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);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }


    上述代码主要分为三段:

    1. 第一段是检查JMX 支持
    2. 第二段创建Boostrap 实 例并初始化
    3. 第三段根据启动参数,执行进一步操作

    第一阶段

    乍一看,第一段似乎可有可无。它只是创 建了一个不被使用的ObjectName 对象,如果创建失败,就打印一条错误信息。而 且在Tomcat 6 中,已经移除了这段代码。

        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;
        }


    这段代码的作用是什么呢?这其实和J2SE 1.4 的兼容性有关。Tomcat 5 使用JMX 作为管理和监控机制,但是J2SE 1.4 本身并不支持JMX ,像ObjectName 这些JMX 类 并不包括J2SE 1.4API 中。因此,Tomcat 5 不能直接运行 在J2SE 1.4 及之前版本上。

    但是Tomcat 5 的设计目标是支持运行在J2SE 1.4 上的。因此,要达到这个目标,Tomcat 5 须 将JMX 类作为兼容包(compatibility package )额外添加到Tomcat 启动类路径中。
    我 们有两种方法获得兼容包:

    1. Tomcat 的官方下载 页面下载兼容包,参见http://tomcat.apache.org/download-55.cgi
    2. 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 ,看完了第一段,我们进入正题,看看第二段代码。

     

    第二阶段

        if (daemon == null) {
            daemon = new Bootstrap();
            try {
                daemon.init();
            } catch (Throwable t) {
                t.printStackTrace();
                return;
            }
        }


    可见,这段代码的主要逻辑在Bootstrapinit 方法。该方法的工作包括:

    1. 设 置CatalinaTomcat Servlet 容器的代号)的路径:CATALINA_HOMECATALINA_BASE
    2. 初始化Tomcat 的类加载器体系
    3. 创建org.apache.catalina.startup.Catalina 对 象(启动阶段剩余的工作由Catalina类 完成)


    为了 节省篇幅,init 方法的代码另文表述 。下面我们看看第三段代码。

     

    第三阶段

    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);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }


    容 易看出,这段代码的主要逻辑就是根据不同的启动参数,执行不同的工作。可以接受的启动参数包括4 种:startd stopd start stop

    启动参数决定了启动还是停止Tomcat 。如何启动,如何停止,另文表述 。本文问想讨论的问题是:除了startstop ,为什么 还有startdstopd ? 它们有什么区别呢?

     

    启动参数的区别

    我们先看看startstartd 。处理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 命 令,从而停止Tomcatshutdown.bat 就是通过这种方式关闭Tomcat , 它最终执行的命令是:
    java [options] org.apache.catalina.startup.Bootstrap stop

    如果启动参数是stopd,那么 Bootstrap将直接调用Catalina的stop方法,直接停止Tomcat。

    综上所述,以start 启动,就以stop 停 止;以startd 启动,就以stopd 停 止。

    如果将Tomcat 作为独立的进程运行,那么应该使用startstop ,这样 我们就可以通过网络停止Tomcat

    如果将Tomcat 以嵌入到应用进程的方式运行(例如Eclipse 中运行Tomcat ), 那么应该使用startdstopd 。 这样,宿主程序通过普通的方法调用,来启动和停止Tomcat

     

    一个Bug

    关于这4 个启动参数的讨论,可以参见Bug 47881 。这个Bug 的本意是要指出第三段代码的一个问题 ,不过恰好讨论了各种启动参数的区别。

    至于这个Bug ,也比较明显:

    1. args[0] = "start"; 应该是 args[args.length - 1 ] = "start";
    2. args[0] = "stop"; 应该是 args[args.length - 1 ] = "stop";

    这 个Bug 已经在Tomcat 6 中解决了。

     

    Tomcat 7中引入的configtest启动参数

    在Tomcat 7中,新增了configtest启动参数。

    public static void main(String args[]) {
                // 省略部分代码
                if (command.equals("startd")) {
                    args[args.length - 1] = "start";
                    daemon.load(args);
                    daemon.start();
                // 省略部分代码
                } else if (command.equals("configtest")) {
                    daemon.load(args);
                    if (null==daemon.getServer()) {
                        System.exit(1);
                    }
                    System.exit(0);
                } else {
                // 省略部分代码
    }

     

    顾名思义,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。

    分享到:
    评论
    6 楼 jzzwy 2014-04-16  
    好文章 支持
    5 楼 jxwnhj0717 2012-04-13  
    好文章!支持
    4 楼 jarfield 2010-03-28  
    ZHH2009 写道
    如果是出于工作目的,工作中还在用Tomcat5,看看Tomcat5的源代码还有点价值。

    如果是出于纯粹的研究目的,想了解一下最新的情况,
    那么看Tomcat5的源代码并没有多大用处,Tomcat5目前应该算是处于维护阶段了。

    推荐你去看看最新的Tomcat7,虽然没正式发布,但是变动还是相当大的,
    比如所有的代码基几乎都转到Java 5了,还删掉了很多冗余的文件,
    增加了很多新功能(特别是异步API的实现)。


    多谢提醒!选择5.5版,确实是出于工作需要,呵呵。如果能够把5.5研究清楚,我想再去看7,应该会轻松很多。
    3 楼 ZHH2009 2010-03-28  
    如果是出于工作目的,工作中还在用Tomcat5,看看Tomcat5的源代码还有点价值。

    如果是出于纯粹的研究目的,想了解一下最新的情况,
    那么看Tomcat5的源代码并没有多大用处,Tomcat5目前应该算是处于维护阶段了。

    推荐你去看看最新的Tomcat7,虽然没正式发布,但是变动还是相当大的,
    比如所有的代码基几乎都转到Java 5了,还删掉了很多冗余的文件,
    增加了很多新功能(特别是异步API的实现)。
    2 楼 wind1373290 2010-03-28  
    nice - 看过Tomcat6的源码,后面看不下去了
    今天看LZ的讲解,相当到位
    这么好的文章,不能停止,加油咯^_^
    1 楼 bluemusic 2010-03-27  
    好像比较详细,排版也不错,支持LZ

    相关推荐

      tomcat 5.5.26

      Apache Tomcat 5.5.26 是一个广泛使用的开源软件,它是一个符合Java Servlet和JavaServer Pages(JSP)规范的应用服务器,主要用于部署和运行Java Web应用程序。Tomcat是Apache软件基金会Jakarta项目的一部分,它以...

      apache-tomcat-5.5.26.rar

      在描述中提到,Tomcat服务器是免费且开放源代码的,这意味着任何人都可以访问其源代码,对其进行修改并自由分发。它的轻量级特性意味着它对系统资源的需求相对较低,特别适合中小规模的Web应用程序。此外,Tomcat ...

      apache-tomcat-5.5.26 免安装

      这个"apache-tomcat-5.5.26 免安装"版本是专为那些不想进行复杂安装过程的用户设计的,只需解压缩即可立即使用。 Tomcat 5.5.26 是该服务器的一个特定版本,发布于2008年,是Tomcat 5.x系列中的一个稳定版本。在这...

      apache-tomcat-5.5.26+apache-tomcat-5.5.26-admin.zip

      1. **Tomcat 5.5.26**: 这是Apache Tomcat的一个较早版本,发布于2008年。Tomcat遵循Java EE规范中的Servlet和JSP标准,它提供了一个轻量级、高效的Web服务器和应用服务器。5.5.x系列是Tomcat的稳定版本,对许多企业...

      apache-tomcat-5.5.26

      Apache Tomcat 5.5.26 是一个广泛使用的开源软件,它是一个符合Java Servlet和JavaServer Pages(JSP)规范的应用服务器,主要用于部署和运行Java Web应用程序。这个版本的Tomcat是在Java EE 5标准下开发的,因此它...

      Tomcat 5.5.26

      Tomcat 5.5.26是一款历史悠久且广受欢迎的开源Web应用程序服务器,由Apache软件基金会的Jakarta项目开发。它主要用于部署和运行Java Servlets和JavaServer Pages (JSP)。Tomcat是Java EE(企业版)的一部分,尽管它...

      Apache tomcat 5.5.26_src.zip

      这个压缩包"Apache tomcat 5.5.26_src.zip"包含了Tomcat 5.5.26版本的源代码,对于开发者来说,它是深入理解Tomcat工作原理、定制或扩展其功能的重要资源。 Apache Tomcat 的主要功能包括: 1. **Servlet容器**:...

      tomcat5.5.26.zip

      另一个文件“apache-tomcat-5.5.26”看起来是Tomcat服务器的解压后的核心目录,其中包含了运行Tomcat所需的所有文件,比如启动脚本、配置文件、Web应用程序的默认目录(webapps)、日志文件存放位置(logs)、临时...

      RHEL5 +Apache2.2.6+Tomcat5.5.26整合

      ### RHEL5 + Apache2.2.6 + Tomcat5.5.26 整合:构建高效Web服务器环境 #### 第一部分:安装与配置Apache2.2.6 Apache作为全球广泛使用的Web服务器软件之一,其稳定性与性能备受好评。在本教程中,我们将学习如何...

      手把手教你使用jk插件配置Tomcat5.5.26与Apache2.2.9

      2. **解压Apache源代码**:对于开发者,"httpd-2.2.9-win32-src.zip"包含Apache的源代码,你可以从中了解其工作原理或自定义编译配置。 3. **JK插件(mod_jk)的获取**:"mod_jk-1.2.26-httpd-2.2.4.so"是适用于...

      apache-tomcat-5.5.26.zip

      Apache Tomcat 5.5.26 是一个广泛使用的开源软件,它是一个符合Java Servlet和JavaServer Pages(JSP)规范的应用服务器,主要用于部署和运行Java Web应用程序。Tomcat是Apache软件基金会Jakarta项目的一部分,以其...

      tomcat-5.5.26

      总之,Tomcat 5.5.26是一个功能强大且易用的Java Web服务器,它为开发者提供了一个轻量级、高效的平台,用于构建和运行基于Java技术的Web应用程序。在实际应用中,我们需要根据具体需求对其进行配置和优化,以达到...

      tomcat-5.5.26集成了richfaces-demo

      "tomcat-5.5.26集成了richfaces-demo" 这个标题表明我们讨论的是一个特定版本的Tomcat服务器——Tomcat 5.5.26,它已经预装了一个名为"richfaces-demo"的示例应用。RichFaces是一个JavaServer Faces (JSF)组件库,...

      Tomcat 5.5.26 Administration Tool HTTP Status 500 临时解决

      用于解决使用 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...

      apache-tomcat-5.5.26加载admin文件

      打开D:\apache-tomcat-5.5.26\conf下的tomcat-users.xml,添加下面一句: xml 代码 roles="admin,manager"/> 启动tomcat,然后打开IE:http://localhost:8080,点击Tomcat Administration即可进入Tomcat server ...

    Global site tag (gtag.js) - Google Analytics