一个context代表一个web应用,它运行在特定的虚拟主机中,每个web应用要么是一个war文件,要么是一个符合规范的目录。一般HTTP请求路径中带有requestURI,我们可以从requestURI中获取上下文路径,根据上下文路径可以选择适合的web应用程序来处理这个请求。你还可以定义多个context,但每个context的名称必须唯一。
context一般会出现在以下三个地方:
(1)、放到web应用的/META-INF/context.xml中,此时如果copyXML属性为true,会将其被拷贝到 $CATALINA_BASE/conf/[enginename]/[hostname]/ 目录中,并命名为应用名;
(2)、直接放到$CATALINA_BASE/conf/[enginename]/[hostname]/ 目录下,该文件将总是优先于/META-INF/context.xml部署;
(3)、server.xml文件的Host元素下面
并不推荐将context直接写在server.xml文件中,因为修改server.xml文件不会导致重新部署,必须重新启动tomcat才会生效,但是在server.xml文件中可以定义多个context元素,其他两种情况不允许。此外,$CATALINA_BASE/conf/context.xml这个文件会被所有web应用加载,$CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default会被同一台主机的所有web应用加载。
standardContext是Context的标准实现,下面来看看这个类在初始化和启动的时候都做了些什么事。
tomcat在启动的过程中是怎么从host过渡到context的?记得在hostconfig类中在部署web应用的时候会调用host.addChild()方法将context挂在host名下作为它的子容器
从上图可以看出在调用host.addChild()方法时触发了child的start方法,再生命周期循环到context的initInternal方法
看看这个方法的代码:
protected void initInternal() throws LifecycleException { super.initInternal(); if (processTlds) { this.addLifecycleListener(new TldConfig()); } // Register the naming resources if (namingResources != null) { namingResources.init(); } // Send j2ee.object.created notification if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.object.created", this.getObjectName(), sequenceNumber.getAndIncrement()); broadcaster.sendNotification(notification); } }很简单做了两件事:1、添加tld标签配置文件监听器;2、发送对象创建的消息,这涉及到JMX的知识,需要找个时间专门研究。
比initInternal方法复杂得多,大体上做了以下几件事:
1、构建webappclassLoader;
2、从CharsetMapperDefault.properties中获取字符集,默认只支持两种en=ISO-8859-1和fr=ISO-8859-1
3、创建工程目录workdir=work/enginename/hostname/contextname
4、context启动完后,随即启动它的附属组件:loader,logger,pipeline,sessionManager等
5、触发contextconfig.lifecycleEvent调用contextConfig.lifecycleEvent处理web.xml配置文件
5、启动它的每个wrapper子容器
6、加载和初始始化那些标识"load on startup"的servlet类
reloadable:如果你需要监视 /WEB-INF/classes/ 和/WEB-INF/lib目录下的文件,就把它设置为true吧,变化后会重载web应用,开发的时候很有用,默认为false,常常提到的重新部署和重新加载,两者之间的区别后续再分析。