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


    本系列转载自 http://blog.csdn.net/haitao111313/article/category/1179996 

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

      在明白这个问题前要先了解一下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文件:

        

    1. digester.addObjectCreate("Server/Service",  
    2.                                 "org.apache.catalina.core.StandardService",  
    3.                                 "className");// 添加一个模式“Server/Service”,当在xml文件(这里是server.xml)里遇到“Server”标签下的Service标签的时候,根据标签Service的属性“className”为类名实例化一个对象,默认类名是"org.apache.catalina.core.StandardServer"  
    4.        digester.addSetProperties("Server/Service"); //设置对象StandardService的属性,有些什么属性由xml里的Service标签指定  
    5.        digester.addSetNext("Server/Service",  
    6.                            "addService",  
    7.                            "org.apache.catalina.Service");//调用Service标签的上一级标签Server的对象(即StandardServer)的addService方法,把Service添加进Server,设置它们的关系,最后一个参数表示addService方法的参数类型  
    这样StandardServer和StandardService便有了所属关系,现在看容器跟链接器是怎么连接的,再看createStartDigester方法:

    1. digester.addObjectCreate("Server/Service/Connector",  
    2.                                  "org.apache.catalina.connector.http.HttpConnector",  
    3.                                  "className");  
    4.         digester.addSetProperties("Server/Service/Connector");  
    5.         digester.addSetNext("Server/Service/Connector",  
    6.                             "addConnector",  
    7.                             "org.apache.catalina.Connector");  

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

    1. public void addConnector(Connector connector) {  
    2.      synchronized (connectors) {  
    3.          connector.setContainer(this.container); //本来这里就应该把容器和连接器关联上的,但是在一开始tomcat启动的时候,Digester是先添加链接器,所以容器container还是为null的,但是没有关系,后面还会另一个地方关联他们,这里应该牢记的是容器和连接器都是在Service里面  
    4.          connector.setService(this);  
    5.          Connector results[] = new Connector[connectors.length + 1];  
    6.          System.arraycopy(connectors, 0, results, 0, connectors.length);  
    7.          results[connectors.length] = connector;  
    8.          connectors = results;  
    9.   
    10.          if (initialized) {  
    11.              try {  
    12.                  connector.initialize();  
    13.              } catch (LifecycleException e) {  
    14.                  e.printStackTrace(System.err);  
    15.              }  
    16.          }  
    17.   
    18.          if (started && (connector instanceof Lifecycle)) {  
    19.              try {  
    20.                  ((Lifecycle) connector).start();  
    21.              } catch (LifecycleException e) {  
    22.                  ;  
    23.              }  
    24.          }  
    25.   
    26.          // Report this property change to interested listeners  
    27.          support.firePropertyChange("connector"null, connector);  
    28.      }  
    29.   
    30.  }  
    这个方法很简单,就是把一个链接器connector添加到StandardService的connectors数组里,然后关联上StandardService的容器。代码上也做了一点说明(很重要)。连接器添加进StandardService了,现在看容器是什么时候添加进StandardService的,其实方法是一样的,再回到createStartDigester方法:

    1. digester.addRuleSet(new EngineRuleSet("Server/Service/"));//这句代码是在createStartDigester方法里面  
    2. --------------------------》下面进入EngineRuleSet类的addRuleInstances方法  
    3. public void addRuleInstances(Digester digester) {  
    4.        digester.addObjectCreate(prefix + "Engine",  
    5.                                 "org.apache.catalina.core.StandardEngine",  
    6.                                 "className");  
    7.        digester.addSetProperties(prefix + "Engine");  
    8.        digester.addRule(prefix + "Engine",  
    9.                         new LifecycleListenerRule  
    10.                         (digester,  
    11.                          "org.apache.catalina.startup.EngineConfig",  
    12.                          "engineConfigClass"));  
    13.        digester.addSetNext(prefix + "Engine",  
    14.                            "setContainer",  
    15.                            "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方法:

    1. public void setContainer(Container container) {  
    2.      Container oldContainer = this.container;  
    3.      if ((oldContainer != null) && (oldContainer instanceof Engine))  
    4.          ((Engine) oldContainer).setService(null);  
    5.      this.container = container;  
    6.      if ((this.container != null) && (this.container instanceof Engine))  
    7.          ((Engine) this.container).setService(this);  
    8.      if (started && (this.container != null) &&  
    9.          (this.container instanceof Lifecycle)) {  
    10.          try {  
    11.              ((Lifecycle) this.container).start();  
    12.          } catch (LifecycleException e) {  
    13.              ;  
    14.          }  
    15.      }                                     //重点!!!!!!!!  
    16.      synchronized (connectors) {           //下面是把StandardService下的所有连接器都关联上StandardService下的容器,这样连接器就跟容器关联上了。  
    17.          for (int i = 0; i < connectors.length; i++)  
    18.              connectors[i].setContainer(this.container);  
    19.      }  
    20.      if (started && (oldContainer != null) &&  
    21.          (oldContainer instanceof Lifecycle)) {  
    22.          try {  
    23.              ((Lifecycle) oldContainer).stop();  
    24.          } catch (LifecycleException e) {  
    25.              ;  
    26.          }  
    27.      }  
    28.   
    29.      // Report this property change to interested listeners  
    30.      support.firePropertyChange("container", oldContainer, this.container);  
    31.   
    32.  }  

    上面的代码做了各种判断,然后把容器设置到StandardService下,在“同步代码块”处,把容器和链接器关联上了,至此,容器和链接器就关联上了。回过头想想,其实很简单,就是用Digester根据设定的模式读取server.xml,然后调用了两个关键的方法setContainer和addConnector,就把容器和链接器关联上了。关联上了就可以明白在Tomcat源码分析(二)--连接处理一文的最后process方法里代码:connector.getContainer().invoke(request, response);的含义了。下篇希望说明白调用invoke之后发生的一切。
  • 相关阅读:
    基于visual Studio2013解决面试题之1101差值最小
    基于visual Studio2013解决面试题之1009兄弟字符串
    基于visual Studio2013解决面试题之1007鸡蛋和篮子
    基于visual Studio2013解决面试题之1006判断升序
    4.16 删除重复记录
    4.9 当相应行存在时更新
    4.8 在表中编辑记录
    4.7 阻止对某几列插入
    4.6 一次向多个表中插入记录
    4.4 从一个表向另外的表中复制行
  • 原文地址:https://www.cnblogs.com/chenying99/p/2798436.html
Copyright © 2020-2023  润新知