前情回顾
上一篇文章主要了解了一下Tomcat启动入口,以及初步的分析了Tomcat的启动流程,下面我们将会解密Tomcat应用部署的实际流程。
一、直观对比
虽然前面已经说了那么多关于Tomcat的东西,但是我相信绝大部分同学应该都没有专门的去研究过Tomcat的内部实现。
我们接触最多的应该还是上传一个war包丢在webapps目录下,然后重启一下Tomcat服务器(甚至不重启)。下面我们以图形的形式,直观的对比Tomcat各组件的关系。
二、应用部署与加载流程分析
下面就针对应用部署与加载流程展开分析
2.1 部署方式
-
隐式部署
直接丢文件夹、war、jar 到 webapps 目录,tomcat 会根据文件夹名称自动生成虚拟路径,简单,但是需要重启 Tomcat 服务器,包括要修改端口和访问路径的也需要重启。
-
显示部署
添加 context 元素 server.xml 中的 Host 加入一个 Context(指定路径和文件地址),例如:
<Host name="localhost">
<Context path="/myapp" docBase="/opt/work_tomcat/myapp.war" />
</Host>
即/myapp 这个虚拟路径映射到了 /opt/work_tomcat/myapp 目录下(war 会解压成文件),修改完 server.xml 需要重启 tomcat 服务器。
-
创建 xml 文件
在 conf/Catalina/localhost 中创建 xml 文件,访问路径为文件名,例如:在 localhost 目录下新建 demo.xml,内容为:
<Context docBase="/opt/work_tomcat/myapp" />
不需要写 path,虚拟目录就是文件名 demo,path 默认为/demo,添加 demo.xml 不需要重启 tomcat 服务器。
2.2 Web应用加载
Web应用加载属于Server启动的核心处理过程。Catalina对Web应用的加载主要由
StandardHost、
HostConfig、
StandardContext、
ContextConfig、
StandardWrapper这5个类完成。
2.2.1 StandardHost
-
当显示部署时,Context元素将会作为Host容器的子容器添加到Host实例当中,并在Host启动时,由生命周期管理接口的start()方法启动。
-
大多数情况下,我们使用的其实都是隐式部署。我们需要关注的是Digester解析器默认为StandardHost容器添加了一个HostConfig监听器。
@Override
publicvoid addRuleInstances(Digester digester) {
digester.addObjectCreate(prefix + "Host","org.apache.catalina.core.StandardHost",
"className");
digester.addSetProperties(prefix + "Host");
digester.addRule(prefix + "Host",
new CopyParentClassLoaderRule());
digester.addRule(prefix + "Host",
new LifecycleListenerRule("org.apache.catalina.startup.HostConfig",
"hostConfigClass"));
//省略部分代码...
}
2.2.2 HostConfig
HostConfig处理的生命周期事件包括:START_EVENT、PERIODIC_EVENT、STOP_EVENT。其中,前两者都与Web应用部署密切相关,后者用于在Host停止时注销其对应的MBean。
逻辑在Host启动时触发START_EVENT事件,完成服务器启动过程中的Web应用部署(只有当Host的deployOnStartup属性为true时,服务器才会在启动过程中部署Web应用,该属性默认值为true)。
public class HostConfig implements LifecycleListener {
/**
* Process a "start"