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

系统 1649 0
本系列转载自 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之后发生的一切。

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


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论