博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
探秘Tomcat——连接篇
阅读量:6305 次
发布时间:2019-06-22

本文共 14709 字,大约阅读时间需要 49 分钟。

  前两篇我们分别粗线条和细粒度的讲解了tomcat的服务是如何启动以及连接器Connector和容器Container又分别是如何被启动的

  本篇我们主要侧重tomcat中server、service以及connector和container之间是如何相互关联起来的。在此之前,我们分别看下这个类中的一些主要方法,尤其是用于相互关联绑定的方法。

 

  Server:(Server代表了整个Catalina容器,一个server可以包含一个或多个Services)

 

1   getInfo                    //获取server的版本 2     getGlobalNamingResources 3     setGlobalNamingResources 4     getPort                    //返回监听关闭server的端口 5     setPort 6     getShutdown                //返回关闭server的命令字符串比如"SHUTDOWN" 7     setShutdown 8     addService                //在该server上添加一个service 9     await                    //一直监听,直到出现shutdown指令10     findService                //返回指定名称的service11     findServices            //返回所有在这个server上的services集合12     removeService13     initialize

 

 

  Service:(Service是一组包含了一个Container和一个或多个Connector的集合)

1   getContainer            //返回容器,该容器用于处理Service上的Connectors发送过来请求 2     setContainer 3     getInfo                    //返回Service的版本信息 4     getName                    //返回该Service的名字 5     setName 6     getServer                //返回与此Service关联的Server,这与Server中的addService遥相呼应 7     setServer                //绑定一个Server 8     addConnector            //添加一个Connector 9     findConnectors            //返回该Service上的所有Connector    10     removeConnector            //删除指定的Connector,同时也以为该Connector与Container也解除联系11     initialize12     addExecutor                //添加一个执行器13     findExecutors14     getExecutor15     removeExecutor

 

  Connector:(前面已经说过,一个Service中可以包含多个Container,但是只会有一个Connector,而Container有多层实现关系,并且有自己的实现规范,所以定义成了接口,而这里的Connector就是一个类而非接口)

1 Connector 2     Connector                    //构造函数,其中有设置Connector要用到的协议 3     getProperty                    //根据属性名,返回属性值 4     setProperty 5     getAttribute                //也是根据属性名,返回属性值,但是getProperty返回的是String类型,这里是Object对象 6     setAttribute 7     removeProperty 8     getService                    //返回与之绑定的Service 9     setService                    //绑定Service10     getAllowTrace11     setAllowTrace                //设置allowTrace,用于跟踪http的信息12     isAvailable                    //判断是否可用于处理request,里面判断的标记是started,这意味着只有Connector启动了才能用于处理request13     getBufferSize                14     setBufferSize15     getContainer                //返回当前Connector移交request的接收Container对象16     setContainer17     getEmptySessionPath18     setEmptySessionPath19     getEnableLookups20     setEnableLookups21     getInfo                        //返回Connector的版本信息22     getMapper23     getMaxHeaderCount            //返回Container允许的最大headers个数24     setMaxHeaderCount25     getMaxParameterCount        //返回GET和POST方法的最大个数26     setMaxParameterCount27     ...28     getPort                        //返回监听request的端口29     setPort30     getProtocol                    //返回使用到的protocol handler,有Http/1.1和AJP/1.331     setProtocol32     getProtocolHandlerClassName33     setProtocolHandlerClassName34     getProtocolHandler35     getProxyName                //设置代理的名字36     setProxyName37     getProxyPort38     setProxyPort39     getRedirectPort                //重定向端口,如果40     setRedirectPort41     getScheme42     setScheme43     getSecure44     setSecure45     getURIEncoding                //返回URI编码46     setURIEncoding47     getUseBodyEncodingForURI48     setUseBodyEncodingForURI49     getXpoweredBy50     setXpoweredBy51     setUseIPVHosts52     getUseIPVHosts53     getExecutorName54     createRequest                //创建或指派并返回Request对象,这里的Request有和Container关联55     createResponse56     addLifecycleListener57     findLifecycleListeners58     removeLifecycleListener59     createObjectName60     initialize                    //初始化Connector对象61     pause                        62     resume63     start64     stop65     ...66     init67     destroy68     toString

 

  Container:(Container可以执行来自客户端的Request请求,并返回相应的Response)

getInfo    getLoader                    //返回与此Container相关的Loader对象,如果没有Loader,则返回与其父Container关联的Loader    setLoader    getLogger                    //返回Logger对象,用于打印log,同理如果当前没有Logger对象,则寻找父级Logger    getManager                    //返回Manager对象    setManager    getMappingObject            //返回JMX对象名字    getObjectName    getPipeline                    //返回与此Container相关的用于管理Valves的Pipeline    getCluster    setCluster    getBackgroundProcessorDelay    setBackgroundProcessorDelay    getName    setName    getParent                    //返回父级Container    setParent    getParentClassLoader        //返回父级类加载器        setParentClassLoader    getRealm    setRealm    getResources    setResources    backgroundProcess    addChild                    //添加一个子容器,在添加之前,需要在子容器中先调用setParent方法    addContainerListener        //添加事件监听器    addPropertyChangeListener    //添加属性值变化监听器        findChild    findChildren    findContainerListeners    invoke                        //执行具体的Request,并得到具体的Response对象    removeChild    removeContainerListener    removePropertyChangeListener    logAccess

 

1.连接原理举例

 

 

  首先我们在Catalina类的load方法中调用了方法createStartDigester,该方法在之前几篇有介绍过,主要是对于加载的server.xml文件中定义各个组件之间的关系。

  比如方法中的片段:

digester.addObjectCreate("Server",                         "org.apache.catalina.core.StandardServer",                         "className");digester.addSetProperties("Server");digester.addSetNext("Server",                    "setServer",                    "org.apache.catalina.Server");

 

  • addObjectCreate就是添加一个模式,当解析server.xml遇到Server的时候,就根据Server的className实例化一个Server对象,而默认实例化的类就是org.apache.catalina.core.StandardServer;
  • addSetProperties用于设置Server的一些属性,具体属性在server.xml中有定义;
  • addSetNext用于调用Server类的setServer方法,把当前Server添加进去。

 

 

  再比如这几行代码:

digester.addObjectCreate("Server/Listener",                         null, // MUST be specified in the element                         "className");digester.addSetProperties("Server/Listener");digester.addSetNext("Server/Listener",                    "addLifecycleListener",                    "org.apache.catalina.LifecycleListener");

 

  对应在server.xml中就是这几行

 

1 
2
3
4
5
6
7
8
9

 

 

  • 同理addObjectCreate说的是在Server下的Listeners,根据className创建listener对象;
  • addSetProperties用于设置Server的一些属性,具体属性在server.xml中有定义;
  • addSetNext用于调用Server类的addLifecycleLisntener方法,把server.xml中定义的5个监听器都实例化并添加到server上。

 

  还有关于Server和Service之间关系的代码

 

digester.addObjectCreate("Server/Service",                         "org.apache.catalina.core.StandardService",                         "className");digester.addSetProperties("Server/Service");digester.addSetNext("Server/Service",                    "addService",                    "org.apache.catalina.Service");

 

  通过这些代码我们很容易理解Server和Service之间的关联关系(后面会详细介绍)

 

 

  除了Server和Service之间的从属关系,我们还可以看到Service和Connector之间的关系

 

digester.addRule("Server/Service/Connector",                 new ConnectorCreateRule());digester.addRule("Server/Service/Connector",                  new SetAllPropertiesRule(new String[]{"executor"}));digester.addSetNext("Server/Service/Connector",                    "addConnector",                    "org.apache.catalina.connector.Connector");

 

  同理这里也是在Service下调用addConnector添加Connector(后面会详细介绍)

 

2.Connector和Container以及Connector和Service何时连接?

 

 

  我们从Catalina的load方法开始,当执行到load中的digester.parse(inputSource)时,即跳转到Digester类的parse方法中,之后开始解析server.xml中依次遇到的各个元素。

 

  当遇到server元素的时候,在代码中方法的执行顺序为Catalina.load->Digester.parse->Digester.startElement

 

  startElement方法如下:

 

1 public void startElement(String namespaceURI, String localName, 2                          String qName, Attributes list) 3         throws SAXException { 4     boolean debug = log.isDebugEnabled(); 5  6     if (saxLog.isDebugEnabled()) { 7         saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + 8                 qName + ")"); 9     }10 11     // Parse system properties12     list = updateAttributes(list);13 14     // Save the body text accumulated for our surrounding element15     bodyTexts.push(bodyText);16     if (debug) {17         log.debug("  Pushing body text '" + bodyText.toString() + "'");18     }19     bodyText = new StringBuffer();20 21     // the actual element name is either in localName or qName, depending22     // on whether the parser is namespace aware23     String name = localName;24     if ((name == null) || (name.length() < 1)) {25         name = qName;26     }27 28     // Compute the current matching rule29     StringBuffer sb = new StringBuffer(match);30     if (match.length() > 0) {31         sb.append('/');32     }33     sb.append(name);34     match = sb.toString();35     if (debug) {36         log.debug("  New match='" + match + "'");37     }38 39     // Fire "begin" events for all relevant rules40     List rules = getRules().match(namespaceURI, match);41     matches.push(rules);42     if ((rules != null) && (rules.size() > 0)) {43         for (int i = 0; i < rules.size(); i++) {44             try {45                 Rule rule = (Rule) rules.get(i);46                 if (debug) {47                     log.debug("  Fire begin() for " + rule);48                 }49                 rule.begin(namespaceURI, name, list);50             } catch (Exception e) {51                 log.error("Begin event threw exception", e);52                 throw createSAXException(e);53             } catch (Error e) {54                 log.error("Begin event threw error", e);55                 throw e;56             }57         }58     } else {59         if (debug) {60             log.debug("  No rules found matching '" + match + "'.");61         }62     }63 64 }
Digester.startElement

 

 

当执行到rule.begin(namespaceURI, name, list)这行的时候,通过调试信息可以看到该rule的className为org.apache.catalina.core.StandardServer,所以最终会进入StandardServer的构造函数中。

 

  另外,当解析server.xml到5个listener的时候,就会调用StandardServer的addLifecycleListener分别将这5个监听器实例化并添加到server上。

 

 

  继续解析,当解析到

igester.addSetNext("Server/Service/Connector",                    "addConnector",                    "org.apache.catalina.connector.Connector");

  的时候就会跳转到StandardService的addConnector方法中

 

 

1 public void addConnector(Connector connector) { 2  3     synchronized (connectors) { 4         connector.setContainer(this.container); 5         connector.setService(this); 6         Connector results[] = new Connector[connectors.length + 1]; 7         System.arraycopy(connectors, 0, results, 0, connectors.length); 8         results[connectors.length] = connector; 9         connectors = results;10 11         if (initialized) {12             try {13                 connector.initialize();14             } catch (LifecycleException e) {15                 log.error(sm.getString(16                         "standardService.connector.initFailed",17                         connector), e);18             }19         }20 21         if (started && (connector instanceof Lifecycle)) {22             try {23                 ((Lifecycle) connector).start();24             } catch (LifecycleException e) {25                 log.error(sm.getString(26                         "standardService.connector.startFailed",27                         connector), e);28             }29         }30 31         // Report this property change to interested listeners32         support.firePropertyChange("connector", null, connector);33     }34 35 }

 

 

  首先解析到的是server.xml中的这个connector

 

 

  下面的两行代码交代了一个Connector是如何关联上Container和Service的:

  • connector.setContainer(this.container):说明了connector和container是如何关联的,调用connector对象的setContainer方法,而传进的值为this.Container,也就是当前StandardService的Container对象,这样就完成了Connector和Container之间的连接
  • connector.setService(this):对外这里绑定了当前的StandardService作为其从属的service。

 

3.Service和Container是何时连接的?

 

  继续解析直到Catalina.createStartDigester定义的

digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));

 

  这时候会调用StandardService的setContainer方法:

 

1 public void setContainer(Container container) { 2  3     Container oldContainer = this.container; 4     if ((oldContainer != null) && (oldContainer instanceof Engine)) 5         ((Engine) oldContainer).setService(null); 6     this.container = container; 7     if ((this.container != null) && (this.container instanceof Engine)) 8         ((Engine) this.container).setService(this); 9     if (started && (this.container != null) &&10         (this.container instanceof Lifecycle)) {11         try {12             ((Lifecycle) this.container).start();13         } catch (LifecycleException e) {14             ;15         }16     }17     synchronized (connectors) {18         for (int i = 0; i < connectors.length; i++)19             connectors[i].setContainer(this.container);20     }21     if (started && (oldContainer != null) &&22         (oldContainer instanceof Lifecycle)) {23         try {24             ((Lifecycle) oldContainer).stop();25         } catch (LifecycleException e) {26             ;27         }28     }29 30     // Report this property change to interested listeners31     support.firePropertyChange("container", oldContainer, this.container);32 33 }

 

  当执行到((Engine) this.container).setService(this);这里会跳转到StandardEngine的setService交代了container是如何绑定StandardService的。

 

  并且在代码

1 synchronized (connectors) {2     for (int i = 0; i < connectors.length; i++)3         connectors[i].setContainer(this.container);4 }

  我们可以看到通过遍历所有的connector,将其与container绑定。

 

4.Server和Service又是何时连接的?

 

 

  继续解析直到Catalina.createStartDigerster中的

digester.addSetNext("Server/Service",                    "addService",                    "org.apache.catalina.Service");

 

  会调用StandardServer的addService方法

 

1 public void addService(Service service) { 2  3     service.setServer(this); 4  5     synchronized (services) { 6         Service results[] = new Service[services.length + 1]; 7         System.arraycopy(services, 0, results, 0, services.length); 8         results[services.length] = service; 9         services = results;10 11         if (initialized) {12             try {13                 service.initialize();14             } catch (LifecycleException e) {15                 log.error(e);16             }17         }18 19         if (started && (service instanceof Lifecycle)) {20             try {21                 ((Lifecycle) service).start();22             } catch (LifecycleException e) {23                 ;24             }25         }26 27         // Report this property change to interested listeners28         support.firePropertyChange("service", null, service);29     }30 31 }

 

  service.setServer(this):该行会调用StandardService中的setServer为service绑定当前的StandardServer对象

 

5.小结

 

 

  当server.xml中的rule解析完毕后,我们起码明白了:

 

  • Server和Service是如何关联的;
  • Service和Connector是如何关联的;
  • Service和Container是如何关联的;
  • Connector和Container是如何关联的

 

 

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。

 

 

友情赞助

如果你觉得博主的文章对你那么一点小帮助,恰巧你又有想打赏博主的小冲动,那么事不宜迟,赶紧扫一扫,小额地赞助下,攒个奶粉钱,也是让博主有动力继续努力,写出更好的文章^^。

    1. 支付宝                          2. 微信

                      

 

转载于:https://www.cnblogs.com/bigdataZJ/p/TomcatSourceZJ6.html

你可能感兴趣的文章
Echart:前端很好的数据图表展现工具+demo
查看>>
CATransform3D iOS动画特效详解
查看>>
Linux VNC黑屏(转)
查看>>
Java反射简介
查看>>
react脚手架应用以及iview安装
查看>>
shell学习之用户管理和文件属性
查看>>
day8--socket网络编程进阶
查看>>
node mysql模块写入中文字符时的乱码问题
查看>>
仍需"敬请期待"的微信沃卡
查看>>
分析Ajax爬取今日头条街拍美图
查看>>
内存分布简视图
查看>>
POJ 2918 求解数独
查看>>
如何学习虚拟现实技术vr? vr初级入门教程开始
查看>>
第4 章序列的应用
查看>>
Mysql explain
查看>>
初识闭包
查看>>
java tcp socket实例
查看>>
011 指针的算术运算
查看>>
hdu1874畅通工程续
查看>>
rails 字符串 转化为 html
查看>>