应用程序
下面将讨论如何使用一个与Context关联的WebappLoader。Context容器的标准实现是org.apache.catalina.core.StandardContext,程序中将使用StandardContext类作为Context容器。StandardContext类将在后面章节讨论,现在不需要知道太多关于这个类的细节。你只需要知道StandardContext与一个监听器协同,监听它派发的START_EVENT和STOP_EVENT事件。监听器必须实现org.apache.catalina.lifecycle.LifecycleListener接口并且调用StandardContext类的setConfigured方法。在这个应用中,监听器为ex08.pyrmont.core.SimpleContextConfig类,代码如下:
package ex08.pyrmont.core;
import org.apache.catalina.Context;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
public class SimpleContextConfig implements LifecycleListener {
public void lifecycleEvent(LifecycleEvent event) {
if (Lifecycle.START_EVENT.equals(event.getType())) {
Context context = (Context) event.getLifecycle();
context.setConfigured(true);
}
}
}
你需要作的就是实例化StandardContext和SimpleContextConfig类,然后调用org.apache.catalina.Lifecycle接口的addLifecycleListener方法将SimpleContextConfig注册到StandardContext中。Lifecycle接口已经在前面章节详细介绍过了。
程序可以使用PrimitiveServlet和ModernServlet这两个servlet来测试,但是和前面章节不同的是,StandardContext类要求servlet的class类要保存在应用的WEB-INF/classes目录下。本章应用的目录为myApp。设置一个名为“catalina.base”的系统属性来告诉StandardContext在哪儿查找应用目录,这个属性的值同属性user.dir的值。如下:
System.setProperty("catalina.base",System.getProperty("user.dir"));
这是Bootstrap类main方法执行的第一行代码,然后main方法会实例化一个默认连接器
Connector connector = new HttpConnector();
然后为两个servlet初始化两个Wrapper容器
Wrapper wrapper1 = new SimpleWrapper();
wrapper1.setName("Primitive");
wrapper1.setServletClass("PrimitiveServlet");
Wrapper wrapper2 = new SimpleWrapper();
wrapper2.setName("Modern");
wrapper2.setServletClass("ModernServlet");
接下来,创建一个StandardContext实例,并设置Context的path和document base。
Context context = new StandardContext();
// StandardContext's start method adds a default mapper
context.setPath("/myApp");
context.setDocBase("myApp");
以上操作相当于在Tomcat的server.xml文件中增加以下配置
<Context path="/myApp" docBase="myApp"/>
接下来,将Wrapper容器添加到Context容器中并注册映射信息,这样Context就可以在不同请求的情况下调用不同的Wrapper。
context.addChild(wrapper1);
context.addChild(wrapper2);
// context.addServletMapping(pattern, name);
context.addServletMapping("/Primitive", "Primitive");
context.addServletMapping("/Modern", "Modern");
下一步是初始化一个监听器,并在Context容器中注册这个监听器
LifecycleListener listener = new SimpleContextConfig();
((Lifecycle) context).addLifecycleListener(listener);
然后实例化WebappLoader,将它与Context容器关联
// here is our loader
Loader loader = new WebappLoader();
// associate the loader with the Context
context.setLoader(loader);
完成以上工作之后,将Context容器与默认连接器关联,调用连接器的initialize和start方法,这样servlet容器就可以工作了。
connector.setContainer(context);
try {
connector.initialize();
((Lifecycle) connector).start();
((Lifecycle) context).start();
接下来的代码中只是在控制台打印资源的docBase和加载器中所有的库。
// now we want to know some details about WebappLoader
WebappClassLoader classLoader = (WebappClassLoader) loader.getClassLoader();
System.out.println("Resources' docBase: "+ ((ProxyDirContext)classLoader.getResources()).getDocBase());
String[] repositories = classLoader.findRepositories();
for (int i = 0; i < repositories.length; i++) {
System.out.println(" repository: " + repositories[i]);
}
最后,程序会一直运行直到在控制台输入回车符停止。
// make the application wait until we press a key.
System.in.read();
((Lifecycle) context).stop();
运行程序
启动程序控制台输出
HttpConnector Opening server socket on all host IP addresses
HttpConnector[8080] Starting background thread
WebappLoader[/myApp]: Deploying class repositories to work directory C:\Users\Administrator\git\HowTomcatWorks\work\_\_\myApp
WebappLoader[/myApp]: Deploy class files /WEB-INF/classes to C:\Users\Administrator\git\HowTomcatWorks\myApp\WEB-INF\classes
Starting Wrapper Primitive
Starting Wrapper Modern
StandardManager[/myApp]: Seeding random number generator class java.security.SecureRandom
StandardManager[/myApp]: Seeding of random number generator has been completed
Resources' docBase: C:\Users\Administrator\git\HowTomcatWorks\myApp
repository: /WEB-INF/classes/
关闭程序时控制台输出
Stopping wrapper Primitive
Stopping wrapper Modern
总结
Web应用加载器,或是一个简单的加载器,是Catalina中最重要的组件。一个加载器使用其内部的类加载器来加载类文件。在Tomcat中,这个内部的类加载器是一个定制的加载器,在一个Web应用中它执行相应的规则来加载一个类。同时,这个定制的类加载器支持缓存以及是否类文件被修改过。