您的位置:首页 > 运维架构 > Tomcat

Tomcat源码学习(11)-How Tomcat works(转)

2009-08-17 04:10 483 查看

ServletProcessor1类

Listing 2.6中的ex02.pyrmont.ServletProcessor1类用于处理servlet的HTTP请求。

Listing 2.6: ServletProcessor1类

package ex02.pyrmont;

import java.net.URL;

import java.net.URLClassLoader;

import java.net.URLStreamHandler;

import java.io.File;

import java.io.IOException;

import javax.servlet.Servlet;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

public class ServletProcessor1 {

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

URL[] urls = new URL[1];

URLStreamHandler streamHandler = null;

File classPath = new File(Constants.WEB_ROOT);

// the forming of repository is taken from the

// createClassLoader method in

// org.apache.catalina.startup.ClassLoaderFactory

String repository =(new URL("file", null, classPath.getCanonicalPath() +

File.separator)).toString() ;

// the code for forming the URL is taken from

// the addRepository method in

// org.apache.catalina.loader.StandardClassLoader.

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 (ClassNotFoundException 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());

}

}

}

ServletProcessor1类出奇的简单,仅仅由一个方法组成:process。这个方法接受两个参数:一个

javax.servlet.ServletRequest实例和一个javax.servlet.ServletResponse实例。该方法从ServletRequest中通过调用getRequestUri方法获得URI:

String uri = request.getUri();

请记住URI是以下形式的:

/servlet/servletName

在这里servletName是servlet类的名字。

要加载servlet类,我们需要从URI中知道servlet的名称。我们可以使用process方法的下一行来获得servlet的名字:

String servletName = uri.substring(uri.lastIndexOf("/") + 1);

接下去,process方法加载servlet。要完成这个,你需要创建一个类加载器并告诉这个类加载器要加载的类的位置。对于这个servlet容器,类加载器直接在Constants指向的目录里边查找。WEB_ROOT就是指向工作目录下面的webroot目录。

注意: 类加载器将在第8章详细讨论。

要加载servlet,你可以使用java.net.URLClassLoader类,它是java.lang.ClassLoader类的一个直接子类。一旦你拥有一个URLClassLoader实例,你使用它的loadClass方法去加载一个servlet类。现在举例说明URLClassLoader类是straightforward直接转发的。这个类有三个构造方法,其中最简单的是:

public URLClassLoader(URL[] urls);

这里urls是一个java.net.URL的对象数组,这些对象指向了加载类时候查找的位置。任何以/结尾的URL都假设是一个目录。否则,URL会Otherwise, the URL假定是一个将被下载并在需要的时候打开的JAR文件。

注意:在一个servlet容器里边,一个类加载器可以找到servlet的地方被称为资源库(repository)。

在我们的应用程序里边,类加载器必须查找的地方只有一个,如工作目录下面的webroot目录。因此,我们首先创建一个单个URL组成的数组。URL类提供了一系列的构造方法,所以有很多中构造一个URL对象的方式。对于这个应用程序来说,我们使用Tomcat中的另一个类的相同的构造方法。这个构造方法如下所示。

public URL(URL context, java.lang.String spec, URLStreamHandler hander)

throws MalformedURLException

你可以使用这个构造方法,并为第二个参数传递一个说明,为第一个和第三个参数都传递null。不过,这里有另外一个接受三个参数的构造方法:

public URL(java.lang.String protocol, java.lang.String host,

java.lang.String file) throws MalformedURLException

因此,假如你使用下面的代码时,编译器将不会知道你指的是那个构造方法:

new URL(null, aString, null);

你可以通过告诉编译器第三个参数的类型来避开这个问题,例如。

URLStreamHandler streamHandler = null;

new URL(null, aString, streamHandler);

你可以使用下面的代码在组成一个包含资源库(servlet类可以被找到的地方)的字符串,并作为第二个参数,

String repository = (new URL("file", null,

classPath.getCanonicalPath() + File.separator)).toString() ;

把所有的片段组合在一起,这就是用来构造适当的URLClassLoader实例的process方法中的一部分:
// create a URLClassLoader

URL[] urls = new URL[1];

URLStreamHandler streamHandler = null;

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);

注意: 用来生成资源库的代码是从org.apache.catalina.startup.ClassLoaderFactory的createClassLoader方法来的,而生成URL的代码是从org.apache.catalina.loader.StandardClassLoader的addRepository方法来的。不过,在以下各章之前你不需要担心这些类。

当有了一个类加载器,你可以使用loadClass方法加载一个servlet:

Class myClass = null;

try {

myClass = loader.loadClass(servletName);

}

catch (ClassNotFoundException e) {

System.out.println(e.toString());

}

然后,process方法创建一个servlet类加载器的实例, 把它向下转换(downcast)为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());

}


运行应用程序

要在Windows上运行该应用程序,在工作目录下面敲入以下命令:

java -classpath ./lib/servlet.jar;./ ex02.pyrmont.HttpServer1

在Linux下,你使用一个冒号来分隔两个库:

java -classpath ./lib/servlet.jar:./ ex02.pyrmont.HttpServer1

要测试该应用程序,在浏览器的地址栏或者网址框中敲入:

http://localhost:8080/index.html

或者

http://localhost:8080/servlet/PrimitiveServlet

当调用PrimitiveServlet的时候,你将会在你的浏览器看到下面的文本:

Hello. Roses are red.

请注意,因为只是第一个字符串被刷新到浏览器,所以你不能看到第二个字符串Violets are blue。我们将在第3章修复这个问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: