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

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章修复这个问题。
原文地址:https://www.cnblogs.com/macula7/p/1960787.html