standardHost
StandardHost加载web应用(StandardContext)有两个入口:
1、context元素部署
Catalina构造Server实例时,在Host元素中增加Context子元素,Context元素将作为Host容器的子容器添加到Host实例中,在Host启动时,由Lifecycle接口的 start() 方法启动(并调用子容器的 start() 方法),配置如下:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context docbase="myApp" path="/myApp" reloadable="true" />
其中:docbase为web应用的根目录,可以是绝对路径,也可以是相对路径(相对于appBase而言)。
path为请求的URL路径
注意:修改前备份配置文件($ sed -ri.bak '/(<!--)/,/(-->)/d' server.xml)
(1)创建myApp目录并重启tomcat
$ mkdir webapps/myApp/ [test@tomcat myApp]$ vim index.jsp <%@ page language="java" %> <%@ page import="java.util.*" %> <html> <head> <title>JSP Test Page</title> </head> <body> <% out.println("Hello,world."); %> </body> </html> $ sudo systemctl restart tomcat
(2)测试访问
[root@iZzm446eh1ux98Z conf]# curl http://localhost:8080 hello,world.
该方式部署的优缺点
缺点:每次部署新应用或删除旧应用的时候,都要修改server.xml文件
优点:
a、适用部署固定的web应用,且应用需要分别在不同目录进行管理,不同host,可以配置不同的appBase
b、可以实现Context定制,增加Context安全管理
StandardHost启动的过程如下:
1、为Host添加一个Valve实现ErrorReportValve,主要用于服务器处理异常时输出错误页
2、调用StandardHost父类ContainerBase的startInternal()方法启动虚拟主机,处理过程分为如下几步:
- 如果配置集群组件Cluster,则启动
- 如果配置了安全组件Realm,则启动
- 启动子节点(server.xml中定义 <Context>创建的实例)
- 启动Host的Pipeline组件
- 设置Host状态为STARTING,触发START_EVENT生命周期事件,HostConfig监听该事件,扫描web目录,对于部署描述文件、WAR包、目录会自动创建StandardContext。
- 启动Host层级的后台任务。
HostConfig部署
START_EVENT生命周期事件在启动Host时触发(只有当Host的deployOnStartup属性设置为true(默认)的时候,服务器才会在启动时部署Web应用)。
有三种部署应用的方式(都是热部署):
- Context描述文件部署
- WAR包部署
- web目录部署
Context描述文件部署
此方式同server.xml中的<Context>元素,配置文件的存储路径由Host的xmlBase指定,默认是在$CATALINA_BASE/conf/<Engine名>/<Host名>,即$CATALINA_BASE/conf/Catalina/localhost目录。
1、创建文件
[test@tomcat apache-tomcat-8.5.6]$ vim conf/Catalina/www.test.com/myApp.xml
<Context docBase="test/myApp" path="/abcd" reloadable="false">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
[test@tomcat apache-tomcat-8.5.6]$ tree webapps/test/ webapps/test/ └── myApp └── index.jsp
cat webapps/test/myApp/index.jsp <%@ page language="java" %> <%@ page import="java.util.*" %> <html> <head> <title>JSP Test Page</title> </head> <body> <% out.println("Helloa,world."); %> </body> </html>
2、访问测试
$ curl -I http://www.test.com:8080/test/myApp/ HTTP/1.1 200 Set-Cookie: JSESSIONID=B6E58C760D9311E59BCCA562292ECD2E;path=/test;HttpOnly Content-Type: text/html;charset=ISO-8859-1 Transfer-Encoding: chunked Date: Thu, 03 Jun 2021 09:23:27 GMT
3、该方式的部署过程如下
(1)扫描Host配置文件基础目录,$CATALINA_BASE/conf/<Engine名>/<Host名>,对该目录下的所有配置文件,由线程池解析完成部署
(2)对于每个文件的部署线程,会做如下操作:
- 使用Digester解析配置文件,创建Context实例
- 更新Context实例名称、路径(在不考虑webappVersion的情况下,使用文件名),所以该文件中的Context元素配置的path不生效,只有在server.xml中path才有效
- 为Context添加ContextConfig生命周期监听器
- 通过Host的addChild()方法将Context实例添加到Host
- 将Context描述文件、web应用目录及web.xml等添加到守护资源。以便文件发生变更时(使用资源文件的上次修改时间进行判断),重新部署或加载web应用
Web目录部署
将所有资源文件(js、css、图片、JSP)、jar包、描述文件的目录复制到Host指定的appBase目录下。
注意:Host的deployIgnore属性可以将符合某个正则表达式的web应用目录忽略而不进行部署,如果不指定,则部署所有目录
此方式下,Catalina同样支持使用配置文件实例化Context(默认在web应用的META-INF目录下,文件名context.xml),可以在配置文件中对Context进行定制,但是无法覆盖name、path、webappVersion、docBase这四个属性,这些由web目录的路径及名称确定
该部署的过程如下:
(1)对于Host的appBase目录($CATALINA_BASE/webapps)下所有符合条件的目录(不符合deployIgnore的过滤规则,且目录名不为META-INF和WEB-INF),有线程池完成部署
(2)对于每个文件的部署线程,会做如下操作:
如果Host的deployXML属性为true(通过Context描述文件部署),并且存在META-INF/context.xml文件,使用Digester解析配置文件,创建Context实例。如果copyXML为true,则将描述文件复制到$CATALINA_BASE/conf/<Engine名>/<Host名>目录下,文件名与web应用目录名相同
如果Host的deployXML属性为false,并且存在META-INF/context.xml文件,则构造FailedContext实例(Catalina的空模式,部署失败)
其他情况下,根据Host的contextClass属性指定的类型创建Context对象。如果不指定,则为org.apache.catalina.core.StandardContext。
为Context添加ContextConfig生命周期监听器
通过Host的addChild()方法将Context实例添加到Host
(1)测试部署
$ mkdir webapps/myApp2/META-INF -p $ vim webapps/myApp2/META-INF/context.xml # 添加如下内容 <Context> docBase="myApp2" path="/myApp2" reloadable="false"</Context> $ echo 1 >> webapps/myApp2/index.html
(2)访问测试
$ curl http://www.test.com:8080/myApp2/index.html 1
WAR包部署
直接将WAR包上传到webapps目录即可。