`
shenkun_918
  • 浏览: 26732 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

tomcat源码分析三

阅读更多

            这里看下tomcat中责任链模式的使用。首先看下什么是责任链模式,责任链模式是抽象的处理者和具体的处理者组成。而具体处理者都拥有其下家的应用,从而形成处理链。直到有处理者处理,并且可以任意扩展链的长度。从简单点的开始,在阎宏《java与模式》一书中,有一个击鼓传花的例子。对责任链模式有很好的讲解,这里就不啰嗦了。通过书中例子,应该可以理解责任链的处理方式,这里主要看下tomcat中的使用。

        首先我们来看下tomcat的配置文件,在conf/server.xml里面。

这个事原始配置文件:

<Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"     connectionTimeout="20000" redirectPort="8443"/>
   <Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
    <Engine name="Catalina" defaultHost="localhost">
         <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
           <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
            </Host>
    </Engine>
</Service>

按照需求更改后的<Engine></Engine>以内的配置文件,其他部分没有变动:

 

<Host name="wap.**.cc" appBase="d:/test/wapPortal" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
   <Context crossContext="true" debug="5" displayName="tawap" docBase="d:/test/wapPortal" path="" reloadable="true">
    <Resource auth="Container" name="jdbc/wapportal" type="javax.sql.DataSource" maxWait="10000" maxIdle="30" maxActive="100" username="root" password="admin" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/onetouch?useUnicode=true&characterEncoding=UTF-8"/>
<ResourceLink global="jdbc/wapportal" name="jdbc/wapportal" type="javax.sql.DataSource"/>
   </Context>
</Host>
<Host name=www.**.com appBase="d:/test" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
 <Context path="/" reloadable="true" docBase="d:/test"> 
 </Context>
</Host>

 tomcat对这部分的处理,就是采用责任链的模式。接下来看下实现责任链的类关系,如图:

tomcat责任链

那么从tomcat哪部分是配置文件呢?我们看下StandardService代码

public class StandardService implements Lifecycle, Service, MBeanRegistration

 依照责任链模式,显然和UML图中的不属于同一个类别,所以其他的部分不构成责任链。由责任链的定义,我们主要看下其上家和下家的定义。

1.首先StandardEngine类:

//setParent方法(上家),可以看出是没有上家的
public void setParent(Container container) {
        throw new IllegalArgumentException
            (sm.getString("standardEngine.notParent"));

    }
//addChild方法如下(下家),可以看到Host为其下家
public void addChild(Container child) {
        if (!(child instanceof Host))
            throw new IllegalArgumentException
                (sm.getString("standardEngine.notHost"));
        super.addChild(child);
}
//有必要设置默认值
public void setDefaultHost(String host) {

        String oldDefaultHost = this.defaultHost;
        if (host == null) {
            this.defaultHost = null;
        } else {
            this.defaultHost = host.toLowerCase();
        }
        support.firePropertyChange("defaultHost", oldDefaultHost,
                                   this.defaultHost);

    }

 2.依照这个顺序,很明显接下来看下Host了。

  //下家为Context
public void addChild(Container child) {
        if (child instanceof Lifecycle) {
            ((Lifecycle) child).addLifecycleListener(
                    new MemoryLeakTrackingListener());
        }
        if (!(child instanceof Context))
            throw new IllegalArgumentException
                (sm.getString("standardHost.notContext"));
        super.addChild(child);
}

 

3.Context的处理,standContext类中addChild方法,可以从代码中看出下家是Wrapper。

   Wrapper oldJspServlet = null;

        if (!(child instanceof Wrapper)) {
            throw new IllegalArgumentException
                (sm.getString("standardContext.notWrapper"));
        }

        Wrapper wrapper = (Wrapper) child;

 

4.Wrapper对应实现

 

//可以看到这层到了责任链处理的终点了
public void addChild(Container child) {
        throw new IllegalStateException
            (sm.getString("standardWrapper.notChild"));
}
//该类中还限制了其上家
public void setParent(Container container) {

        if ((container != null) &&
            !(container instanceof Context))
            throw new IllegalArgumentException
                (sm.getString("standardWrapper.notContext"));
        if (container instanceof StandardContext) {
            swallowOutput = ((StandardContext)container).getSwallowOutput();
            unloadDelay = ((StandardContext)container).getUnloadDelay();
        }
        super.setParent(container);

    }

 

tomcat启动的时候,是肯定要从配置文件读取数据启动的,那么是怎么来启动这个链的呢?接下来看下这部分的启动,

首先是standardEngine类中的启动了。

  // Standard container startup
        super.start();

 那么看下父类中的启动代码了,即CantainerBasestart()如下:

  Container children[] = findChildren();
        for (int i = 0; i < children.length; i++) {
            if (children[i] instanceof Lifecycle)
                ((Lifecycle) children[i]).start();
        }

 根据上面的代码addChild和这里的 findChildren(),维护了一个链。这样就可以按照配置文件的不同配置,来启动加载了。

         同时,我们可以看到的是责任链的整个部分都实现了观察者的Lifecycle接口,从而它们都是在观察者模式中处于主题对象的角色。观察者对象对其作相应的处理,启动前,启动,启动后,观察者会有不同的处理。在stop()中有关闭的处理,这里看下启动部分start()中观察者处理代码,。

//start中的部分代码
// Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
        started = true;
        //省略部分代码
       // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(START_EVENT, null);

        // Start our thread
        threadStart();

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics