`
haitaoandroid
  • 浏览: 27736 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Tomcat源码分析(三)--连接器是如何与容器关联的?

 
阅读更多

这篇文章要弄懂一个问题,我们知道,一个链接器是跟一个容器关联的,容器跟链接器是在什么时候关联上的?

  在明白这个问题前要先了解一下Digester库,这个库简单的说就是解析xml文件,这里有两个概念:模式和规则,所谓模式就是一个xml的标签,规则就是遇到一个xml标签需要做什么,看一下他主要的三个方法:

1:addObjectCreate(String pattern, String className, String attributeName) 根据模式pattern实例化一个对象className

2:addSetProperties(String pattern) 设置这个模式的属性

3:addSetNext(String pattern, String methodName, String paramType) 添加模式之间的关系,调用父模式的

上面可能不好理解,看tomcat是怎么用到Digester的,在org.apache.catalina.startup.Catalina.createStartDigester()的方法里(这个方法是在服务组件启动的时候调用的,详细参考Tomcat源码分析(一)--服务启动),在这个方法里有使用Digester来解析server.xml文件:

 

 digester.addObjectCreate("Server/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className");// 添加一个模式“Server/Service”,当在xml文件(这里是server.xml)里遇到“Server”标签下的Service标签的时候,根据标签Service的属性“className”为类名实例化一个对象,默认类名是"org.apache.catalina.core.StandardServer"
        digester.addSetProperties("Server/Service"); //设置对象StandardService的属性,有些什么属性由xml里的Service标签指定
        digester.addSetNext("Server/Service",
                            "addService",
                            "org.apache.catalina.Service");//调用Service标签的上一级标签Server的对象(即StandardServer)的addService方法,把Service添加进Server,设置它们的关系,最后一个参数表示addService方法的参数类型

这样StandardServer和StandardService便有了所属关系,现在看容器跟链接器是怎么连接的,再看createStartDigester方法:

 

 

digester.addObjectCreate("Server/Service/Connector",
                                 "org.apache.catalina.connector.http.HttpConnector",
                                 "className");
        digester.addSetProperties("Server/Service/Connector");
        digester.addSetNext("Server/Service/Connector",
                            "addConnector",
                            "org.apache.catalina.Connector");


这里很好理解,跟上面的是一样的,遇到标签Server/Service/Connector的时候(这里简化了说法,应该是标签Server下的子标签Service的子标签Connector,有点拗口),实例化HttpConnector,然后在它的上一级父容器StandardService下调用addConnector,这样就把链接器HttpConnector添加进容器StandardService下了,看StandardService的addConnector方法:

 

 

   public void addConnector(Connector connector) {
        synchronized (connectors) {
            connector.setContainer(this.container); //本来这里就应该把容器和连接器关联上的,但是在一开始tomcat启动的时候,Digester是先添加链接器,所以容器container还是为null的,但是没有关系,后面还会另一个地方关联他们,这里应该牢记的是容器和连接器都是在Service里面
            connector.setService(this);
            Connector results[] = new Connector[connectors.length + 1];
            System.arraycopy(connectors, 0, results, 0, connectors.length);
            results[connectors.length] = connector;
            connectors = results;

            if (initialized) {
                try {
                    connector.initialize();
                } catch (LifecycleException e) {
                    e.printStackTrace(System.err);
                }
            }

            if (started && (connector instanceof Lifecycle)) {
                try {
                    ((Lifecycle) connector).start();
                } catch (LifecycleException e) {
                    ;
                }
            }

            // Report this property change to interested listeners
            support.firePropertyChange("connector", null, connector);
        }

    }

这个方法很简单,就是把一个链接器connector添加到StandardService的connectors数组里,然后关联上StandardService的容器。代码上也做了一点说明(很重要)。连接器添加进StandardService了,现在看容器是什么时候添加进StandardService的,其实方法是一样的,再回到createStartDigester方法:

 

 

 digester.addRuleSet(new EngineRuleSet("Server/Service/"));//这句代码是在createStartDigester方法里面
 --------------------------》下面进入EngineRuleSet类的addRuleInstances方法
 public void addRuleInstances(Digester digester) {
        digester.addObjectCreate(prefix + "Engine",
                                 "org.apache.catalina.core.StandardEngine",
                                 "className");
        digester.addSetProperties(prefix + "Engine");
        digester.addRule(prefix + "Engine",
                         new LifecycleListenerRule
                         (digester,
                          "org.apache.catalina.startup.EngineConfig",
                          "engineConfigClass"));
        digester.addSetNext(prefix + "Engine",
                            "setContainer",
                            "org.apache.catalina.Container"); //这里调用StandardService的方法setContainer方法,把容器添加进StandardService里面
}

先不去纠结Digester是怎么进入addRuleInstances方法的,当我们调用了digester.addRuleSet(new EngineRuleSet("Server/Service/"));方法,Digester便会自动调用到EngineRuleSet类的addRuleInstances方法,在方法里面无非也是添加各种模式和规则,根据上面的添加规则,很容易知道这里又添加了一个StandardEngine对象(容器),然后又在该模式的上一级模式Server/Service添加StandardEngine跟StandardService的关系,即通过setContainer方法把容器添加进StandardService里。以下是StandardService的setContainer方法:

 

 

   public void setContainer(Container container) {
        Container oldContainer = this.container;
        if ((oldContainer != null) && (oldContainer instanceof Engine))
            ((Engine) oldContainer).setService(null);
        this.container = container;
        if ((this.container != null) && (this.container instanceof Engine))
            ((Engine) this.container).setService(this);
        if (started && (this.container != null) &&
            (this.container instanceof Lifecycle)) {
            try {
                ((Lifecycle) this.container).start();
            } catch (LifecycleException e) {
                ;
            }
        }                                     //重点!!!!!!!!
        synchronized (connectors) {           //下面是把StandardService下的所有连接器都关联上StandardService下的容器,这样连接器就跟容器关联上了。
            for (int i = 0; i < connectors.length; i++)
                connectors[i].setContainer(this.container);
        }
        if (started && (oldContainer != null) &&
            (oldContainer instanceof Lifecycle)) {
            try {
                ((Lifecycle) oldContainer).stop();
            } catch (LifecycleException e) {
                ;
            }
        }

        // Report this property change to interested listeners
        support.firePropertyChange("container", oldContainer, this.container);

    }


上面的代码做了各种判断,然后把容器设置到StandardService下,在“同步代码块”处,把容器和链接器关联上了,至此,容器和链接器就关联上了。回过头想想,其实很简单,就是用Digester根据设定的模式读取server.xml,然后调用了两个关键的方法setContainer和addConnector,就把容器和链接器关联上了。关联上了就可以明白在Tomcat源码分析(二)--连接处理一文的最后process方法里代码:connector.getContainer().invoke(request,response);的含义了。下篇希望说明白调用invoke之后发生的一切。

分享到:
评论

相关推荐

    apache-tomcat-9.0.34-src.zip

    6. **src**:这是最重要的部分,包含了Tomcat所有核心模块的源代码,如Catalina(核心Servlet容器)、 Coyote(HTTP/HTTPS连接器)、Jasper(JSP编译器)等。 7. **common`, `server`, `shared`:这些是类库目录,...

    tomcat源码分析

    ### Tomcat源码分析 #### 一、概述 Apache Tomcat是Java开发人员最常用的Web服务器之一,它不仅能够作为独立的应用程序运行Servlet和JavaServer Pages(JSP),还可以作为一个内嵌的容器来运行Web应用。Tomcat的...

    我的tomcat7源码手撕过程

    1. **连接器接收请求**:`Connector`组件负责监听客户端请求,并将请求传递给适配器。 2. **协议适配器处理请求**:适配器(如`CoyoteAdapter`)将请求解析为内部格式,并调用`ProtocolHandler`处理请求。 3. **容器...

    运行apache-tomcat-7.0.81源码所需的jar包和新建eclipse工程步骤

    在深入研究源码时,建议先了解Servlet和JSP的基本概念,以及Tomcat的核心组件,如Catalina(核心引擎)、 Coyote(HTTP连接器)和 Jasper(JSP编译器)。这将帮助你更好地理解源码中的类和方法的作用。 此外,...

    tomcat 6 源码

    通过研究Tomcat源码,开发者可以学习到如何构建一个高性能的Servlet容器,掌握Java Web应用的核心运行机制,这对于提升Java EE开发能力大有裨益。同时,如果你遇到Tomcat的使用问题或者想要进行定制化开发,源码分析...

    how tomcat works 中文版及源码

    9. **源码分析**:书中提供的源码可以帮助开发者了解Tomcat如何处理请求、调度线程、管理会话等。例如,你可以看到`org.apache.catalina.connector.Request`类如何解析请求,`org.apache.catalina.Container`如何...

    tomcat并发资料

    综上,掌握Tomcat并发处理的知识,结合源码分析和工具应用,能有效地提升服务器的并发处理能力,应对高流量网站的需求。这份"Tomcat并发资料.txt"文件可能包含上述部分或全部知识点的详细解释,是学习和优化Tomcat...

    tomcat _ecplice

    对于源码和工具相关的标签,这意味着我们可能涉及到Tomcat的源代码分析,以及如何使用Eclipse作为开发工具来理解和调试Tomcat。开发者可以通过阅读和修改Tomcat源代码来学习其内部工作原理,提高对Java Web开发的...

    Tomcat 系统架构与设计模式

    Tomcat的核心组件包括Connector(连接器)和Container(容器)。Connector负责与客户端进行通信,接收HTTP请求并返回响应,而Container则负责处理请求,执行Servlet代码,并生成响应。两者结合在Service中,Service...

    Tomcat5&Servlet 原理.doc

    **源码分析** StandardService的`setContainer`和`addConnector`方法展示了如何配置和管理Service的组件。当添加或更改Container时,需要确保与Service正确关联,并可能启动或停止相关的生命周期。同样,添加...

    Java项目实战-物流信息网的设计与实现(附源码,部署说明).zip

    【Java项目实战-物流信息网的设计与实现】是一个基于Java技术的综合项目,旨在提供一个高效、实用的物流信息管理平台。该项目涵盖了软件开发的多个关键环节,包括需求分析、系统设计、数据库构建、编码实现以及部署...

    myeclipse+tomcat6.0+struts2开发的登录程序

    Struts2的动作配置文件(struts.xml)定义了动作映射,关联URL路径到特定的Action类,还可能包含拦截器,用于实现如日志、权限检查等附加功能。 开发步骤可能包括以下内容: 1. **创建项目**:在MyEclipse中新建一...

    基于ssm会议发布与预约系统微信小程序源码数据库文档.zip

    这是一个关于使用SSM(Spring、SpringMVC、MyBatis)框架和微信小程序开发的会议发布与预约系统的毕业设计项目。这个系统旨在提供一个便捷的平台,让用户能够方便地查看会议信息、预约会议以及进行相关的管理操作。...

    基于springboot的蜗牛兼职网源码数据库.zip

    蜗牛兼职网是一个基于SpringBoot框架的项目,用于搭建一个在线兼职信息发布的平台。...通过对源码的分析和研究,开发者可以深入了解SpringBoot如何与SSM、JSP等技术配合,以及如何构建一个完整的Web应用。

    java+mysql学生学籍后台管理系统源码.zip

    这是一个基于Java和MySQL的学生学籍后台管理系统源码项目。该项目主要涵盖了Java编程语言与MySQL数据库在开发管理信息系统方面的应用,适合初学者学习和理解MVC(Model-View-Controller)架构以及数据库操作。 1. *...

    Servlet 介绍 以及Servlet生命周期(详细)

    Servlet是Java Web开发中的核心组件,它是一种...结合源码分析和适当的工具,如调试器和日志记录,可以更好地理解和优化Servlet的性能。在实际项目中,熟练运用Servlet能帮助开发者构建出功能强大、扩展性强的Web应用。

    超级有影响力霸气的Java面试题大全文档

    当客户机第一次调用一个Stateful Session Bean 时,容器必须立即在服务器中创建一个新的Bean实例,并关联到客户机上,以后此客户机调用Stateful Session Bean 的方法时容器会把调用分派到与此客户机相关联的Bean实例...

    基于SSM的二手物品交易平台--项目源码.zip

    10. **部署与测试**:项目完成后,需要在服务器上进行部署,可能使用Tomcat或Jetty等Servlet容器。同时,进行单元测试和集成测试,确保每个功能都能正常工作,例如使用JUnit进行后端测试,使用Selenium进行前端功能...

    基于springboot的个人博客系统源码数据库.doc

    - 嵌入式服务器:支持嵌入Tomcat、Jetty等Web容器。 - 易于使用的依赖启动器:提供了一些约定好的依赖管理方式。 - 独立的应用程序:可以被打包成jar或war格式,方便部署。 2. **Vue.js** - **简介**:Vue.js是...

Global site tag (gtag.js) - Google Analytics