设为首页 收藏本站
查看: 594|回复: 0

[经验分享] tomcat源码分析三

[复制链接]

尚未签到

发表于 2017-1-24 08:38:46 | 显示全部楼层 |阅读模式
  这里看下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对这部分的处理,就是采用责任链的模式。接下来看下实现责任链的类关系,如图:
DSC0000.jpg

  那么从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();
  那么看下父类中的启动代码了,即CantainerBase中start()如下:

  Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children instanceof Lifecycle)
((Lifecycle) children).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);

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-332655-1-1.html 上篇帖子: tomcat out of Memory error 下篇帖子: Tomcat server.xml配置简介
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表