- 浏览: 26466 次
- 性别:
- 来自: 广州
最新评论
这篇文章要弄懂一个问题,我们知道,一个链接器是跟一个容器关联的,容器跟链接器是在什么时候关联上的?
在明白这个问题前要先了解一下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之后发生的一切。
发表评论
-
Tomcat源码分析(一)--服务启动
2012-07-05 11:11 430对Tomcat感兴趣是由 ... -
Tomcat源码分析(二)--连接处理
2012-07-06 08:35 387目标:在这篇文章希望搞明白http请求到tomcat后是 ... -
Tomcat源码分析(四)--容器处理链接之责任链模式
2012-07-07 16:21 359目标:在这篇文章希望搞明白connector.getCont ... -
Tomcat源码分析(五)--容器处理连接之servlet的映射
2012-07-08 09:32 398本文所要解决的问题:一个http请求过来,容器是怎么知道选 ... -
Tomcat源码分析(六)--日志记录器和国际化
2012-07-09 08:34 490日志记录器挺简单的,没有很多东西,最主要的就是一个Lo ... -
Tomcat源码分析(七)--单一启动/关闭机制(生命周期)
2012-07-10 12:23 447在前面的大部分文章都是讲连接器和容器的,以后的内容会偏向写一 ... -
Tomcat源码分析(八)--载入器
2012-07-10 20:14 521在讲Tomcat的载入器之前,先要了解一下java的类加载 ... -
Tomcat源码分析(十)--部署器
2012-07-12 09:02 491我们知道,在Tomcat的世界里,一个Host容器代表一 ... -
Tomcat源码分析(九)--Session管理
2012-07-11 15:16 646在明白Tomcat的Session机 ...
相关推荐
tomcat-redis-session-manager源码
tomcat-redis-session-manager-1.2-tomcat-7-java-7.jar commons-pool-1.6.jar jedis-2.0.0.jar
解决tomcat8-maven-plugin-3.0-r1655215.jar阿里云同有的问题。放到路径org\apache\tomcat\maven\tomcat8-maven-plugin\3.0-r1655215\就可以了
开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-...
apache-tomcat-8.5.20.tar.gz源码包和context.xml文件,这套配置是我自己亲测可用的。。另外我用的redis4这个版本。注意:如果你使用的TOMCAT其他版本。例如tomcat6或者7这套JAR包可能不可用,tomcat8.0没有测试。...
tomcat9负载均衡tomcat-cluster-redis-session-manager_4.0
tomcat6-dta-ssl-1.0.0.jar 此类文件将有助于tomcat支持ssl协议
压缩文件包括tomcat-redis-session-manager-master-2.0.0.jar、jedis-2.7.3.jar、commons-pool2-2.3.jar三个jar包使用方法请参照https://github.com/jcoleman/tomcat-redis-session-manager。apache-tomcat-8.5.33....
Tomcat8亲测可用 tomcat-redis-session-manager的jar包 修改了tomcat-redis-session-manager源码进行的编译生成的jar包
Maven使用tomcat8-maven-plugin插件
用于配置 tomcat-redis-session-manager
apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-...
tomcat-juli.jar和tomcat-juli-adapters.jar tomcat-juli.jar和tomcat-juli-adapters.jar
apache-tomcat-6.0.53-src,apache tomcat 6.0.53的源码。 压缩包文件清单: apache-tomcat-6.0.53-src.tar.gz apache-tomcat-6.0.53-src.tar.gz.asc apache-tomcat-6.0.53-src.tar.gz.md5 apache-tomcat-6.0.53-...
apache-tomcat-7.0.53apache-tomcat-7.0.53apache-tomcat-7.0.53apache-tomcat-7.0.53
7.0.59版本,直接去关联这个压缩包即可.如果版本不对http://archive.apache.org/dist/tomcat/去官网直接下也可以.
maven-tomcat-plugin让maven与tomcat配合得很好。它可以把应用部署到Tomcat服务器,也可以把tomcat作为内嵌服务器启动,就像jetty一样。 使用JPDA启动tomcat的远程调试功能。这样就能与eclipse配合起来,轻松地实现...
tomcat6-maven-plugin-2.1插件包
apache-tomcat-8.0.41-windows-x64 tomcat8最新稳定版, 亲测可用
使用tomcat-redis-session-manager进行统一session管理所需jar包,包括tomcat6-jdk6、tomcat7-jdk7、tomcat8-jdk8