当前页面: 开发资料首页 → JSP 专题 → 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 align="center" border="1" bordercolordark="#FFFFFF" bordercolorlight="black" cellpadding="2" cellspacing="0" width="400">
<tr>
<td bgcolor="e6e6e6" class="code" style="font-size:9pt">
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());
}
}
</td>
</tr>
</table>
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 align="center" border="1" bordercolordark="#FFFFFF" bordercolorlight="black" cellpadding="2" cellspacing="0" width="400">
<tr>
<td bgcolor="e6e6e6" class="code" style="font-size:9pt">
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);
</td>
</tr>
</table>
创建储存库 (repository)的代码摘自org.apache.catalina.startup.ClassLoaderFactory内的createClassLoader 方法,而创建 URL 的代码摘自org.apache.catalina.loader.StandardClassLoader 类内的 addRepository 方法。 但在此阶段您还没有必要去关心这些类。
有了类装载器,您可以使用loadClass方法装载servlet类:
<table align="center" border="1" bordercolordark="#FFFFFF" bordercolorlight="black" cellpadding="2" cellspacing="0" width="400">
<tr>
<td bgcolor="e6e6e6" class="code" style="font-size:9pt">
try {
myClass = loader.loadClass(servletName);
}
catch (ClassNotFoundException e) {
System.out.println(e.toString());
}
</td>
</tr>
</table>
然后,process方法创建已装载的 servlet类的实例,传递给 javax.servlet.Servlet ,并激活 servlet 的 service 方法:
<table align="center" border="1" bordercolordark="#FFFFFF" bordercolorlight="black" cellpadding="2" cellspacing="0" width="400">
<tr>
<td bgcolor="e6e6e6" class="code" style="font-size:9pt">
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());
}
</td>
</tr>
</table>
编译并运行该应用程序
如果要编译该应用程序,在工作目录下键入以下命令:
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 运行工作原理 随后的章节会告诉您怎样来解决这个问题。
【关于作者】
本系列文章由petrel翻译,petrel ,java 爱好者,在深圳从事 java 和数据库的开发工作,喜爱各项运动!也可以点击http://www.matrix.org.cn/user_view.asp?username=petrel查看她的信息.或者通过petrel.zhang@ccjk.com 与她联系.
【原文:】http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html
↑返回目录
前一篇: Servlet容器工作原理讲解(二)
后一篇: Servlet容器工作原理讲解(四)