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

应用程序2

第一个应用程序有一个严重的问题。在ServletProcessor1类的process方法,你向上转换ex02.pyrmont.Request实例为javax.servlet.ServletRequest,并作为第一个参数传递给servlet的service方法。你也向下转换ex02.pyrmont.Response实例为javax.servlet.ServletResponse,并作为第二个参数传递给servlet的service方法。
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) request,(ServletResponse) response);
}
    这会危害安全性。知道这个servlet容器的内部运作的Servlet程序员可以分别把ServletRequest和ServletResponse实例向下转换为ex02.pyrmont.Request和ex02.pyrmont.Response,并调用他们的公共方法。拥有一个Request实例,它们就可以调用parse方法。拥有一个Response实例,就可以调用sendStaticResource方法。
你不可以把parse和sendStaticResource方法设置为私有的,因为它们将会被其他的类调用。不过,这两个方法是在个servlet内部是不可见的。其中一个解决办法就是让Request和Response类拥有默认访问修饰,所以它们不能在ex02.pyrmont包的外部使用。不过,这里有一个更优雅的解决办法:通过使用facade类。请看Figure 2.2中的UML图。
Figure 2.2: Façade classes
在这第二个应用程序中,我们增加了两个façade类: RequestFacade和ResponseFacade。RequestFacade实现了ServletRequest接口并通过在构造方法中传递一个引用了ServletRequest对象的Request实例作为参数来实例化。ServletRequest接口中每个方法的实现都调用了Request对象的相应方法。然而ServletRequest对象本身是私有的,并不能在类的外部访问。我们构造了一个RequestFacade对象并把它传递给service方法,而不是向下转换Request对象为ServletRequest对象并传递给service方法。Servlet程序员仍然可以向下转换ServletRequest实例为RequestFacade,不过它们只可以访问ServletRequest接口里边的公共方法。现在parseUri方法就是安全的了。
Listing 2.7 显示了一个不完整的RequestFacade类
Listing 2.7: RequestFacade类
package ex02.pyrmont;
public class RequestFacade implements ServletRequest {
private ServleLRequest request = null;
public RequestFacade(Request request) {
this.request = request;
}
/* implementation of the ServletRequest*/
public Object getAttribute(String attribute) {
return request.getAttribute(attribute);
}
public Enumeration getAttributeNames() {
return request.getAttributeNames();
}
...
}
    请注意RequestFacade的构造方法。它接受一个Request对象并马上赋值给私有的servletRequest对象。还请注意,RequestFacade类的每个方法调用ServletRequest对象的相应的方法。
这同样使用于ResponseFacade类。
这里是应用程序2中使用的类:
  • HttpServer2
  • Request
  • Response
  • StaticResourceProcessor
  • ServletProcessor2
  • Constants
HttpServer2类类似于HttpServer1,除了它在await方法中使用ServletProcessor2而不是ServletProcessor1:
if (request.getUri().startWith("/servlet/")) {
     servletProcessor2 processor = new ServletProcessor2();
processor.process(request, response);
}
else {
...
}
    ServletProcessor2类类似于ServletProcessor1,除了process方法中的以下部分:
Servlet servlet = null;
RequestFacade requestFacade = new RequestFacade(request);
ResponseFacade responseFacade = new ResponseFacade(response);
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) requestFacade,(ServletResponse)responseFacade);
}

运行应用程序

要在Windows上运行该应用程序,在工作目录下面敲入以下命令:
java -classpath ./lib/servlet.jar;./ ex02.pyrmont.HttpServer2
    在Linux下,你使用一个冒号来分隔两个库:
java -classpath ./lib/servlet.jar:./ ex02.pyrmont.HttpServer2
    你可以使用与应用程序1一样的地址,并得到相同的结果。

总结

本章讨论了两个简单的可以用来提供静态资源和处理像PrimitiveServlet这么简单的servlet的servlet容器。同样也提供了关于javax.servlet.Servlet接口和相关类型的背景信息。
原文地址:https://www.cnblogs.com/macula7/p/1960786.html