HostConfig实现了LifecycleListener接口,因此它是一个监听器,这个监听器的作用是部署应用。那么这个监听器是加在哪个组件上的呢?是何时被添加的呢?我们知道,在Catalina容器启动过程中会加载server.xml配置文件,这是通过Digester库来完成的,注意到Catalina.createStartDigester()方法中有这样几行代码:
digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
这是要向Digester实例中添加多个规则(RuleSet),HostRuleSet继承了RuleSetBase类,并实现了它的抽像方法:addRuleInstances。下面来看这个方法的具体实现:
public void 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")); ... }首先创建了LifecycleListenerRule规则,然后在模式" Server/Service/Engine/Hos"下,将这个规则加到Host之上。这个规则正是tomcat的生命周期规则,因此在Host生命周期过程中会触发这个规则。
以上归纳起来就一句话:HostConfig是一个生命周期监听器类,在tomcat加载配置文件的时候被添加到Host之上。
那么这个监听器是在什么时候触发的呢?
正是在StandardHost启动的时候触发的,其startInternal调用层次比较深,下面以时序图来展示其触发过程:
即在StandardHost启动的过程中,在其父类中改变了生命周期状态,导致这个监听器的触发。
通过下面的类图对HostConfig类一个整体认知:
HostConfig类里面有四个内部类,分别是DeployDescriptor、DeployWar、DeployDirectory、DeployedApplication,其中前3个代表三种不同的部署形式:分别是xml、war包、目录形式,最后一个DeployedApplication代表被部署的应用。从HostConfig类图中可以看到它有一个map类型的字段deployed,这个map的key为一个web应用的上下文件路径,value正是这个web应用被部署之后的一个对象,也就是这个应用对应的DeployedApplication。
前面提到有三种不同的部署形式,其实这三种部署形式步骤都殊途同归,首先讲解tomcat部署web应用的一般步骤,然后详细讲解xml文件的布置,最后再简要分析一下另外两种布署中的不同和需要注意的地方。
布署两个字很抽象,说白了就是创建对象的过程,创建什么对象,就是前面提到的DeployedApplication对象,这个对象要怎么创建,就要先看看这个对象的类图:
以上就是这个类的全部了,包含四个字段和一个构造方法
name:上下文路径
redeployResources:保存可能导致应用重新部署的资源文件,比如context.xml,docBase,目录路径等,这里面的资源如果有修改会导致应用重新部署,如果被删除会导致这个应用被卸载.key为资源名称,value为资源最后一次修改时间
reloadResources:保存可能导致应用重新加载的资源文件,比如web.xml等,同样,key为资源名称,value为资源最后一次修改时间
timestamp:应用最后提供服务的时间
了解了DeployedApplication类之后,部署可以理解为构建DeployedApplication对象,将影响重新部署和重新加载这个应用的资源文件找到并保存起来的过程。
假设在webapps目录下有一个test1.war应用,在{tomcat_home}\conf\Catalina\localhost有一个test2.xml文件,文件内容为
<?xml version='1.0' encoding='utf-8'?> <Context path="/test2" docBase="E:\code\test2\target\test2.war" debug="on" reloadable="true"> </Context>最后deployed里的内容如下图所示:
是在deployDescriptor方法中完成的,步骤如下:
1、利用digester解析出context,为这个context添加contextConfig监听器;
2、判断docbase是否为绝对路径,如果不是,则表明是以webapps为相对路径,将其设置为webapps+docbase;
3、将{tomcat_home}\conf\Catalina\localhost\test2.xml和E:\code\test2\target\test2.war放入redeployResources中;
4、设置context一些字段并调用container的addChild方法,将其设置为host的子容器;
5、将web.xml加入reloadResources中
6、将构造好的DeployedApplication加入deployed中
步骤和xml几乎一样
1、列出webapps中所有文件夹,过滤掉不需要部署的目录和不合法的目录,过滤掉已部署的应用,过滤掉过滤掉META-INF,WEB-INF目录
2、对剩下的目录进行遍历,如果以“.war”结尾,表示是war包,获取/META-INF/context.xml文件,如果不存在,将其看成jar包再次获取
3、后面和部署xml类似
和部署war包类似,不同的是当没有找到/META-INF/context.xml文件时,不会在jar中查找