探秘Tomcat——连接篇
2016-07-23 20:26
537 查看
前两篇我们分别粗线条和细粒度的讲解了tomcat的服务是如何启动以及连接器Connector和容器Container又分别是如何被启动的.
本篇我们主要侧重tomcat中server、service以及connector和container之间是如何相互关联起来的。在此之前,我们分别看下这个类中的一些主要方法,尤其是用于相互关联绑定的方法。
Server:(Server代表了整个Catalina容器,一个server可以包含一个或多个Services)
Service:(Service是一组包含了一个Container和一个或多个Connector的集合)
Connector:(前面已经说过,一个Service中可以包含多个Container,但是只会有一个Connector,而Container有多层实现关系,并且有自己的实现规范,所以定义成了接口,而这里的Connector就是一个类而非接口)
Container:(Container可以执行来自客户端的Request请求,并返回相应的Response)
1.连接原理举例
首先我们在Catalina类的load方法中调用了方法createStartDigester,该方法在之前几篇有介绍过,主要是对于加载的server.xml文件中定义各个组件之间的关系。
比如方法中的片段:
addObjectCreate就是添加一个模式,当解析server.xml遇到Server的时候,就根据Server的className实例化一个Server对象,而默认实例化的类就是org.apache.catalina.core.StandardServer;
addSetProperties用于设置Server的一些属性,具体属性在server.xml中有定义;
addSetNext用于调用Server类的setServer方法,把当前Server添加进去。
再比如这几行代码:
对应在server.xml中就是这几行
同理addObjectCreate说的是在Server下的Listeners,根据className创建listener对象;
addSetProperties用于设置Server的一些属性,具体属性在server.xml中有定义;
addSetNext用于调用Server类的addLifecycleLisntener方法,把server.xml中定义的5个监听器都实例化并添加到server上。
还有关于Server和Service之间关系的代码
通过这些代码我们很容易理解Server和Service之间的关联关系(后面会详细介绍)
除了Server和Service之间的从属关系,我们还可以看到Service和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方法如下:
Digester.startElement
当执行到rule.begin(namespaceURI, name, list)这行的时候,通过调试信息可以看到该rule的className为org.apache.catalina.core.StandardServer,所以最终会进入StandardServer的构造函数中。
另外,当解析server.xml到5个listener的时候,就会调用StandardServer的addLifecycleListener分别将这5个监听器实例化并添加到server上。
继续解析,当解析到
的时候就会跳转到StandardService的addConnector方法中
首先解析到的是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定义的
这时候会调用StandardService的setContainer方法:
当执行到((Engine) this.container).setService(this);这里会跳转到StandardEngine的setService交代了container是如何绑定StandardService的。
并且在代码
我们可以看到通过遍历所有的connector,将其与container绑定。
4.Server和Service又是何时连接的?
继续解析直到Catalina.createStartDigerster中的
会调用StandardServer的addService方法
service.setServer(this):该行会调用StandardService中的setServer为service绑定当前的StandardServer对象
5.小结
当server.xml中的rule解析完毕后,我们起码明白了:
Server和Service是如何关联的;
Service和Connector是如何关联的;
Service和Container是如何关联的;
Connector和Container是如何关联的
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。
本篇我们主要侧重tomcat中server、service以及connector和container之间是如何相互关联起来的。在此之前,我们分别看下这个类中的一些主要方法,尤其是用于相互关联绑定的方法。
Server:(Server代表了整个Catalina容器,一个server可以包含一个或多个Services)
getInfo //获取server的版本 getGlobalNamingResources setGlobalNamingResources getPort //返回监听关闭server的端口 setPort getShutdown //返回关闭server的命令字符串比如"SHUTDOWN" setShutdown addService //在该server上添加一个service await //一直监听,直到出现shutdown指令 findService //返回指定名称的service findServices //返回所有在这个server上的services集合 removeService initialize
Service:(Service是一组包含了一个Container和一个或多个Connector的集合)
getContainer //返回容器,该容器用于处理Service上的Connectors发送过来请求 setContainer getInfo //返回Service的版本信息 getName //返回该Service的名字 setName getServer //返回与此Service关联的Server,这与Server中的addService遥相呼应 setServer //绑定一个Server addConnector //添加一个Connector findConnectors //返回该Service上的所有Connector removeConnector //删除指定的Connector,同时也以为该Connector与Container也解除联系 initialize addExecutor //添加一个执行器 findExecutors getExecutor removeExecutor
Connector:(前面已经说过,一个Service中可以包含多个Container,但是只会有一个Connector,而Container有多层实现关系,并且有自己的实现规范,所以定义成了接口,而这里的Connector就是一个类而非接口)
Connector Connector //构造函数,其中有设置Connector要用到的协议 getProperty //根据属性名,返回属性值 setProperty getAttribute //也是根据属性名,返回属性值,但是getProperty返回的是String类型,这里是Object对象 setAttribute removeProperty getService //返回与之绑定的Service setService //绑定Service getAllowTrace setAllowTrace //设置allowTrace,用于跟踪http的信息 isAvailable //判断是否可用于处理request,里面判断的标记是started,这意味着只有Connector启动了才能用于处理request getBufferSize setBufferSize getContainer //返回当前Connector移交request的接收Container对象 setContainer getEmptySessionPath setEmptySessionPath getEnableLookups setEnableLookups getInfo //返回Connector的版本信息 getMapper getMaxHeaderCount //返回Container允许的最大headers个数 setMaxHeaderCount getMaxParameterCount //返回GET和POST方法的最大个数 setMaxParameterCount ... getPort //返回监听request的端口 setPort getProtocol //返回使用到的protocol handler,有Http/1.1和AJP/1.3 setProtocol getProtocolHandlerClassName setProtocolHandlerClassName getProtocolHandler getProxyName //设置代理的名字 setProxyName getProxyPort setProxyPort getRedirectPort //重定向端口,如果 setRedirectPort getScheme setScheme getSecure setSecure getURIEncoding //返回URI编码 setURIEncoding getUseBodyEncodingForURI setUseBodyEncodingForURI getXpoweredBy setXpoweredBy setUseIPVHosts getUseIPVHosts getExecutorName createRequest //创建或指派并返回Request对象,这里的Request有和Container关联 createResponse addLifecycleListener findLifecycleListeners removeLifecycleListener createObjectName initialize //初始化Connector对象 pause resume start stop ... init destroy 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中就是这几行
<!--APR library loader. Documentation at /docs/apr.html --> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html --> <Listener className="org.apache.catalina.core.JasperListener" /> <!-- Prevent memory leaks due to use of particular java/javax APIs--> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html --> <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
同理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方法如下:
public void startElement(String namespaceURI, String localName, String qName, Attributes list) throws SAXException { boolean debug = log.isDebugEnabled(); if (saxLog.isDebugEnabled()) { saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + qName + ")"); } // Parse system properties list = updateAttributes(list); // Save the body text accumulated for our surrounding element bodyTexts.push(bodyText); if (debug) { log.debug(" Pushing body text '" + bodyText.toString() + "'"); } bodyText = new StringBuffer(); // the actual element name is either in localName or qName, depending // on whether the parser is namespace aware String name = localName; if ((name == null) || (name.length() < 1)) { name = qName; } // Compute the current matching rule StringBuffer sb = new StringBuffer(match); if (match.length() > 0) { sb.append('/'); } sb.append(name); match = sb.toString(); if (debug) { log.debug(" New match='" + match + "'"); } // Fire "begin" events for all relevant rules List rules = getRules().match(namespaceURI, match); matches.push(rules); if ((rules != null) && (rules.size() > 0)) { for (int i = 0; i < rules.size(); i++) { try { Rule rule = (Rule) rules.get(i); if (debug) { log.debug(" Fire begin() for " + rule); } rule.begin(namespaceURI, name, list); } catch (Exception e) { log.error("Begin event threw exception", e); throw createSAXException(e); } catch (Error e) { log.error("Begin event threw error", e); throw e; } } } else { if (debug) { log.debug(" No rules found matching '" + match + "'."); } } }
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方法中
public void addConnector(Connector connector) { synchronized (connectors) { connector.setContainer(this.container); 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) { log.error(sm.getString( "standardService.connector.initFailed", connector), e); } } if (started && (connector instanceof Lifecycle)) { try { ((Lifecycle) connector).start(); } catch (LifecycleException e) { log.error(sm.getString( "standardService.connector.startFailed", connector), e); } } // Report this property change to interested listeners support.firePropertyChange("connector", null, connector); } }
首先解析到的是server.xml中的这个connector
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
下面的两行代码交代了一个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方法:
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) { 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); }
当执行到((Engine) this.container).setService(this);这里会跳转到StandardEngine的setService交代了container是如何绑定StandardService的。
并且在代码
synchronized (connectors) { for (int i = 0; i < connectors.length; i++) connectors[i].setContainer(this.container); }
我们可以看到通过遍历所有的connector,将其与container绑定。
4.Server和Service又是何时连接的?
继续解析直到Catalina.createStartDigerster中的
digester.addSetNext("Server/Service", "addService", "org.apache.catalina.Service");
会调用StandardServer的addService方法
public void addService(Service service) { service.setServer(this); synchronized (services) { Service results[] = new Service[services.length + 1]; System.arraycopy(services, 0, results, 0, services.length); results[services.length] = service; services = results; if (initialized) { try { service.initialize(); } catch (LifecycleException e) { log.error(e); } } if (started && (service instanceof Lifecycle)) { try { ((Lifecycle) service).start(); } catch (LifecycleException e) { ; } } // Report this property change to interested listeners support.firePropertyChange("service", null, service); } }
service.setServer(this):该行会调用StandardService中的setServer为service绑定当前的StandardServer对象
5.小结
当server.xml中的rule解析完毕后,我们起码明白了:
Server和Service是如何关联的;
Service和Connector是如何关联的;
Service和Container是如何关联的;
Connector和Container是如何关联的
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。
相关文章推荐
- IIS+TOMCAT+MYSQL服务器部署的方法与常见问题的解决办法
- Linux上的安装与配置Tomcat
- tomcat的常用配置方法
- tomcat源码解析(二)——xml解析过程分析
- tomcat调优
- mac idea tomcat
- Neither the JAVA_HOME nor the JRE_HOME environment variable is defined 错误&&Eclipse 访问tomcat首页报404错误
- Eclipse中实现Tomcat热部署
- LVS+keepalived+nginx+tomcat部署实现
- Windows 7下配置JDK环境变量,JAVA环境变量配置,Tomcat服务器的使用
- Tomcat7.0安装配置详细
- tomcat导入maven项目运行抛出org.springframework.web.context.ContextLoaderListener not found
- tomcat源码解析(一)——Bootstrap和Catalina启动部分
- tomcat-源码导入eclipse(简化版)
- Maven自动部署至外部Tomcat
- tomcat启动startup.bat一闪而过
- Tomcat单机多实例配置
- 通向架构师的道路(第一天)之Apache整合Tomcat
- linux安装tomcat
- tomcat设置默认项目