Tomcat架构解析之Web应用加载(上篇)

一、Web应用的加载过程

    Web应用加载属于Server启动的核心处理过程。Catalina对Web应用的加载主要有StandardHost、HostConfig、StandardContext、ContextCOnfig、StandardWrapper这5个类完成的。

以一张时序图来展示Catalina对Web应用的加载过程如下所示:
在这里插入图片描述

二、StandardHost

    StandardHost加载Web应用的入口有两个,而且上面的时序图也很好的说明了这一点。其中一个入口时在Catalina构造Server实例时,如果Host元素存在Oontext子元素(server.xml中),那么Context元素将会作为Host容器的子容器添加到Host实例中,并且在Host启动时,由生命周期管理接口的start()方法启动。

Context的配置一般如下所示:

<Host name="localhost" appbase="webapps" unpackWARs="true" autoDeploy="true">
	<Context docBase="myApp" path="/myApp" reloadable="true"/>
</Host>

    其中,docBase为Web应用根目录的文件路径,path为Web应用的根请求地址。如上,加入我们的Tomcat地址为http://127.0.0.1:8080,那么,Web应用的根请求地址为http://127.0.0.1:8080/myApp。

    通过此方式加载,尽管Tomcat处理简单(当解析server.xml时一并完成Context的创建),但对于使用者来说却并不是一种好方式,毕竟,没有人愿意每次部署新的Web应用或者删除旧应用时,都必须改一下server.xml文件。

    当然,如果部署的Web应用相对固定,并且每个应用需要分别在特定的目录下进行管理,那么可以选择这种部署方式。此时,如果仅配置Host,那么所有Web应用需要放置到同一个基础目录下。

    除了Web应用的目录可以任意指定外,这种方式可以实现Context配置的深度定制(如为Context增加安全管理,甚至重新指定Context和Wrapper的实现类),我们可以根据需要添加任何Context支持的属性和子元素,而不局限于其默认配置。

    另外一个入口则是由HostCOnfig自动扫描部署目录,创建Context实例并且启动。这是大多数Web应用的加载方式。

StandarHost的启动加载过程如下所示:
(1)为Host添加一个Valve实现ErrorReportValve,该类主要用于在服务器处理异常时输出错误页面。如果我们没有在web.xml中添加错误处理页面,Tomcat返回的异常栈页面便是由ErrorReportValve生成的。
(2)调用StandardHost父类ContainerBase的startInternal()方法启动虚拟主机,其处理主要分以下几步:

  1. 如果配置了集群组件Cluster,则启动。
  2. 如果配置了安全组件Realm,则启动。
  3. 启动子节点(即通过server.xml中的创建的StandardContext实例)。
  4. 启动Host持有的Pipeline组件。
  5. 设置Host状态为STARTING,此时会触发STAR_EVENT生命周期事件。HostConfig监听该事件,扫描Web部署目录,对于部署描述文件、WAR包、目录会自动创建StandardContext实例,添加到Host并启动。
  6. 启动Host层级的后台任务处理:Cluster后台任务处理(包括部署变更检测、心跳)、Realm后台任务处理、Pipeline中Valve的后台任务处理。

三、HostConfig

    在讲解Server的创建时,HostConfig是一个LifecycleListener实现,并且由Catalina默认添加到Host实例上。

    HostConfig处理的生命周期事件包括:START_EVENT、PERIODIC_EVENT、STOP_EVENT。其中,前两者都与Web应用部署密切相关,后者用于在Host通知时注销其对应的MBean。

1、START_EVENT事件
    该事件在Host启动时触发,完成服务器启动过程中的Web应用部署(只有当Host的deployOnStartup属性为true时,服务器才会在启动过程中部署Web应用,该属性默认为true)。

    该事件处理包含了三个部分:Context描述文件部署、Web目录部署、WAR包部署,而且这3部分对应于Web应用的3类不同的部署方式。

【1】 Context描述文件部署
    Tomcat支持通过一个独立的Context描述文件来配置并且启动Web应用,配置方式同server.xml中的元素。该配置文件的存储路径由Host的xmlBase属性指定。如果未指定,则默认值为 $ CATALINA_BASE/conf/<Engine名称>/<Host名称>,因此,对于Tomcat默认的Host,Context描述文件的路径为$CATALINA_BASE/conf/Catalina/localhost。

Comtext描述文件的部署过程如下所示:
(1)扫描Host配置文件基础目录,即$ CATALINA_BASE/conf/<Engine名称>/<Host名称>,对于该目录下的每个配置文件,由线程池完成解析部署。
(2)对于每个文件的部署线程,进行如下操作:

  1. 使用Digester解析配置文件,创建Context实例。
  2. 更新Context实例的名称、路径,因此元素中的配置的path无效。
  3. 为Context添加ContextConfig生命周期监听器。
  4. 通过Host的addChild()方法将Context实例添加到Host。该方法会盘带你Host是否已经启动,如果是,则直接启动Context。
  5. 将Context描述文件、Web应用目录以及web.xml等添加到守护资源、以便文件发生变更时,重新部署或者加载Web应用。

【2】Web目录部署
    以目录的形式发布并且部署Web应用是Tomcat最常见的部署方式。我们只需要将包含Web应用所有资源文件(JS、CSS、图片、JSP等)、Jar包、描述文件(WEB-INF/web.xml)的目录复制到Host指定appBase目录下即可完成部署。

    此种部署方式下,Catalina同样支持通过配置文件来实例化Context(默认位于Web应用的META-INF目录下,文件名称为context.xml)。我们人可以在配置文件中对Context进行定制,但是无法覆盖name、path、webappVersion、docBase这四个属性,这些均由Web目录的路径以及名称确定。

    Catalina部署Web应用目录的过程如下所示:
(1)对于Host的appBase目录(默认为$ CATALINA_BASE/webapps)下所有符合条件的目录,由线程池完成部署。
(2)对于每个目录进行如下操作:

  1. 如果Host的deployXML属性值为true(即通过Context描述文件部署),并且存在META-INF/context.xml文件,则使用Digester解析context.xml文件创建Context对象。如果Context的copyXML属性为true,则将描述文件复制到$ CATALINA_BASE/conf/<ENGINE名称>/<Host名称>目录下,文件名称于Web应用目录名称相同。
  2. 如果deployXML属性值为false,但是存在META-INF/context.xml文件,则构造failedContext实例(Catalina的空模式,用于表示Context部署失败)。
  3. 为Context实例添加ContextConfig生命周期监听器。
  4. 通过Host的addChild()方法将Context实例添加到Host。该方法会盘带你Host是否已经启动,如果是,则直接启动Context。
  5. 将Context描述文件、Web应用目录以及web.xml等添加到守护资源,以便文件发生变更时重新部署或者加载Web应用。守护文件因deployXML和copyXML的配置稍有不同。

【3】WAR包部署
    WAR部署和WEb目录部署基本类似,只是由于WAR包作为一个压缩文件,增加了部分针对压缩文件的处理

具体的部署过程如下所示:
(1)对于Host的appBase目录(默认为$ CATALINA_BASE/webapps)下所有符合条件的WAR包,由线程池完成部署。
(2)对于每个WAR包进行如下操作:

  1. 如果Host的deployXML属性为true,并且在WAR包同名目录下存在META-INF/context.xml文件,同时Context的copyXML属性问false,则使用该描述文件创建Context实例
  2. 如果Host的deployXML的属性为true,并且在WAR包同名目录下存在META-INF/context.xml文件,则使用该描述文件创建Context对象。
  3. 如果deployXML属性值为false,但是在WAR包压缩文件下存在MEtA-INF/context.xml文件,则后者failedContext实例(Catalina的空模式,用于表示Context部署失败)
  4. 如果deployXML为true,并且META-INF/context.xml存在WAR包中,同时Context的copyXML为true,则将context.xml文件复制到$ CATALINA_BASE/conf/<Engine名称>/<Host名称>目录下,文件名称同WAR名称。
  5. 为Context实例添加ContextConfig生命周期监听器。
  6. 通过Host的addChild()方法将Context实例添加到Host。该方法会判断Host是否已经启动,如果是,则直接启动Context。
  7. 将Context描述文件、WAR包以及web.xml等添加到守护资源,以便文件发送变更时重新部署或者加载Web应用。

2、PERIODIC_EVENT事件
    Catalina的容器支持定期执行自身以及其子容器的后台处理过程(该机制位于所有容器的父类ContainerBase中,默认情况下是由Engine维护后台任务处理线程)。具体处理过程在容器的backgroundProcess()方法中定义。该机制常用于定时描述Web应用的变更,并且进行重新加载。后台任务处理完成后,将触发PERIODIC_EVENT事件。

    在HostConfig中通过DeployedApplication维护了两个守护资源列表:redeployResources和reloadResources,前者用于守护导致应用重新部署资源,后者守护导致应用重新加载的资源。两个列表分别维护了资源及其最后的修改时间。

    当HostConfig接收到PERIODIC_EVENT事件后,会检测守护资源的变更情况。如果发生变更,将重新加载或者部署应用以及更新资源的最后修改时间。

其具体的部署过程如下(只有当Host的autoDeploy属性为tue时处理):
(1)对于每一个已经部署的Web应用,检查用于重新部署的守护资源。对于每一个守护资源文件或者目录,如果发生变更,那么就有一下几种情况:

  • 如果资源对应为目录,则仅更新守护资源列表中的上次修改时间。
  • 如果Web应用存在Context描述文件并且当前变更的WAR包文件,则得到原Context的docBase。如果docBase不以" .war "结尾(即Context指向的是WAR解压目录),删除解压目录并且重新加载,否则直接重新加载,更新守护资源。
  • 其他情况下,直接卸载应用,并且由接下来的处理步骤重新部署。

(2)对于每个已经部署的Web应用,检查用于重新加载的守护资源如果资源发生变更,则重新加载Context对象。
(3)如果Host配置为卸载旧版本应用(undeployOldVersion属性为true),则检查并且卸载。
(4)部署Web应用,部署过程和上面一样。

总结

    回顾上述Web应用的部署方式,无论是Context描述文件,还是Web目录以及WAR包,归结起来,Catalina支持Web应用以文件目录或者WAR包的形式发布;同时,如果希望定制COntext,那么可以通过$ CATALINA_BASE/conf/<Engine名称>/<Host名称>目录下的描述文件或者Web应用的META-INF/context.xml来进行定义。
    因此从这个角度来看,基本可以将Catalina的Web应用部署分为目录和WAR包两类,每一类进一步支持Context的定制化。而默认情况下,Catalina会根据发布包的路径以及名称自动创建一个Context对象。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值