这篇文章要弄懂一个问题,我们知道,一个链接器是跟一个容器关联的, 容器跟链接器是在什么时候关联上的?
在明白这个问题前要先了解一下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方法的参数类型
- 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);
- }
- }
- 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里面
- 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之后发生的一切。
更多文章、技术交流、商务合作、联系博主
微信扫码或搜索:z360901061
微信扫一扫加我为好友
QQ号联系: 360901061
您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。
【本文对您有帮助就好】元