当前页面: 开发资料首页 → J2EE 专题 → Servlet容器工作原理(三)
摘要: Servlet容器工作原理(三)
ServletProcessor1 类
ServletProcessor1 类用来处理对 servlet 的 HTTP 请求。 它非常简单,只包含了一个 process 方法。 而这个方法接受两个参数: 一个javax.servlet.ServletRequest 实例和一个 avax.servlet.ServletResponse实例。 process 方法也构建了一个 java.net.URLClassLoader 对象并使用它装载 servlet 类文件。 在从类装载器获得的 Class 对象上,process 方法创建一个 servlet 实例并调用它的 service 方法。
process 方法
Listing 2.4. ServletProcessor1 类中 process 方法
<table style="TABLE-LAYOUT: fixed" cellSpacing=0 borderColorDark=#ffffff cellPadding=4 width="98%" align=center bgColor=#e6e6e6 borderColorLight=#009ace border=1>
public void process(Request request, Response response) {
String uri = request.getUri();
String servletName = uri.substring(uri.lastIndexOf("/") + 1);
URLClassLoader loader = null;
try {
// create a URLClassLoader
URLStreamHandler streamHandler = null;
URL[] urls = new URL[1];
File classPath = new File(Constants.WEB_ROOT);
String repository = (new URL("file", null,
classPath.getCanonicalPath() + File.separator)).toString() ;
urls[0] = new URL(null, repository, streamHandler);
loader = new URLClassLoader(urls);
}
catch (IOException e) {
System.out.println(e.toString());
}
Class myClass = null;
try {
myClass = loader.loadClass(servletName);
}
catch (Exception e) {
System.out.println(e.toString());
}
Servlet servlet = null;
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) request, (ServletResponse) response);
}
catch (Exception e) {
System.out.println(e.toString());
}
catch (Throwable e) {
System.out.println(e.toString());
}
}
process 方法接受两个参数:一个 ServletRequest实例和一个 ServletResponse 实例。 process方法通过调用 getRequestUri 方法从 ServletRequest获取 URI。
String uri = request.getUri();
切记 URI 的格式:
/servlet/servletName
servletName 是 servlet 类的名称。
如果要装载 servlet 类,则需要使用以下代码从 URI 获知 servlet 名称:
String servletName = uri.substring(uri.lastIndexOf("/") + 1);
然后 process 方法装载 servlet。 要做到这些,需要创建一个类装载器,并告诉装载器该类的位置, 该 servlet 容器可以指引类装载器在 Constants.WEB_ROOT 指向的目录中查找。 在工作目录下,WEB_ROOT 指向 webroot/ 目录。
如果要装载一个 servlet,则要使用 java.net.URLClassLoader 类,它是java.lang.ClassLoader 的间接子类。 一旦有了 URLClassLoader 类的实例,就可以使用 loadClass 方法来装载一个 servlet 类。 实例化 URLClassLoader 是很简单的。 该类有三个构建器,最简单的是:
public URLClassLoader(URL[] urls);
urls 是一组指向其位置 java.net.URL 对象, 当装载一个类时它会自动搜索其位置。 任一以 / 结尾的 URL 都被假定为一目录, 否则,就假定其为 .jar 文件,在需要时可以下载并打开。
在一个 servlet 容器内,类装载器查找 servlet 类的位置称为储存库 (repository)。
在所举的应用程序中,类装载器只可在当前工作目录下的 webroot/ 目录查找,所以,首先得创建一组简单的 URL。 URL 类提供了多个构建器,因此有许多的方法来构建一个 URL 对象。 在这个应用程序内,使用了和 TOMCAT 内另外一个类所使用的相同的构建器。 该构建器头部 (signature) 如下:
public URL(URL context, String spec, URLStreamHandler hander)
throws MalformedURLException
可以通过传递给第二个参数一个规范,传递给第一个和第三个参数 null 值来使用这个构建器, 但在些有另外一种可接受三个参数的构建器:
public URL(String protocol, String host, String file)
throws MalformedURLException
因此,如果只写了以下代码,编译器将不知道是使用的哪个构建器:
new URL(null, aString, null);
当然也可以能过告诉编译器第三个参数的类型来避开这个问题,如:
URLStreamHandler streamHandler = null;
new URL(null, aString, streamHandler);
对于第二个参数,可以传递包含储存库 (repository) 的 String 。 以下代码可创建:
String repository = (new URL("file", null,
classPath.getCanonicalPath() + File.separator)).toString();
结合起来,以下是构建正确 URLClassLoader 实例的 process 方法的部分代码:
<table style="TABLE-LAYOUT: fixed" cellSpacing=0 borderColorDark=#ffffff cellPadding=4 width="98%" align=center bgColor=#e6e6e6 borderColorLight=#009ace border=1>
// create a URLClassLoader
URLStreamHandler streamHandler = null;
URL[] urls = new URL[1];
File classPath = new File(Constants.WEB_ROOT);
String repository = (new URL("file", null,
classPath.getCanonicalPath() + File.separator)).toString() ;
urls[0] = new URL(null, repository, streamHandler);
loader = new URLClassLoader(urls);
创建储存库 (repository)的代码摘自org.apache.catalina.startup.ClassLoaderFactory内的createClassLoader 方法,而创建 URL 的代码摘自org.apache.catalina.loader.StandardClassLoader 类内的 addRepository 方法。 但在此阶段您还没有必要去关心这些类。
有了类装载器,您可以使用 loadClass 方法装载 servlet 类:
<table style="TABLE-LAYOUT: fixed" cellSpacing=0 borderColorDark=#ffffff cellPadding=4 width="98%" align=center bgColor=#e6e6e6 borderColorLight=#009ace border=1>
Class myClass = null;
try {
myClass = loader.loadClass(servletName);
}
catch (ClassNotFoundException e) {
System.out.println(e.toString());
}
然后,process方法创建已装载的 servlet类的实例,传递给 javax.servlet.Servlet ,并激活 servlet 的 service 方法:
Servlet servlet = null;
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) request, (ServletResponse) response);
}
catch (Exception e) {
System.out.println(e.toString());
}
catch (Throwable e) {
System.out.println(e.toString());
}
编译并运行该应用程序
如果要编译该应用程序,在工作目录下键入以下命令:
javac -d . -classpath ./lib/servlet.jar src/ex02/pyrmont/*.java
如果要在 windows 下运行该应用程序,在工作目录下键入以下命令:
java -classpath ./lib/servlet.jar;./ ex02.pyrmont.HttpServer1
在 linux 环境下,使用冒号来隔开类库:
java -classpath ./lib/servlet.jar:./ ex02.pyrmont.HttpServer1
如果要测试该应用程序,请在 URL 或浏览器地址栏键入以下命令:
http://localhost:8080/index.html
或者是:
http://localhost:8080/servlet/PrimitiveServlet
您将会在浏览器中看到以下文本:
Hello. Roses are red.
注意:您不能看到第二行字符 (Violets are blue),因为只有第一行字符送入到浏览器。 Tomcat 运行工作原理 随后的章节会告诉您怎样来解决这个问题。
关于翻译作者:
<table style="TABLE-LAYOUT: fixed" cellSpacing=0 borderColorDark=#ffffff cellPadding=4 width="98%" align=center bgColor=#e6e6e6 borderColorLight=#009ace border=1>
前一篇: Servlet容器工作原理(四)
后一篇: EJB核心技术及其应用