应用程序1中有一个严重的问题。在servletprocessor1类的process()方法中,必须将ex02.pyrmont.request的实例向上转型为javax.servlet.servletrequest实例,将ex02.pyrmont.response实例向上转型为javax.servlet.servletresponse实例,然后将它们作为参数传递给servlet的service()方法:
这是不安全的做法,了解这个servlet容器内部工作原理的servlet程序员可以将servletrequest实例和servletresponse实例分别向下转型为ex02.pyrmont.request实例和ex02.pyrmont.response实例,就可以调用它们各自的公共方法了。有了request实例后,就可以调用其parse()方法;而有了response实例后,就可以调用其sendstaticresource()方法。
不能将parse()方法和sendstaticresource()方法设置为私有方法,因为它们会被其他的类调用,但是这两个方法在servlet中不应该是可用的,所以这个方法不好。一种解决方法是将request类和response类都设为默认的访问修饰符,这样就不能从ex02.pyrmont包外对它们进行访问了。但是,这里有一个更完美的方法:使用外观类。uml 关系图如图2-2所示。
在第2个应用程序中,添加了两个外观类:requestfacade和responsefacade。requestfacade类实现servletrequest接口,在其构造函数中需要把它指定的一个reuqest对象传递给servletrequest对象引用。servletrequest接口中每个方法的实现都会调用request对象的相应方法。但是,servletrequest对象本身是私有的,无法从类的外部进行访问。相比于将request对象向上转型为servletrequest对象,并将其传给service()方法,这里会创建一个requestfacade对象,再将其传递给service()方法。servlet程序员仍然可以将servletrequest实例向下转型为requestfacade对象,但它们只能访问servletrequest接口中提供的方法。现在parse()方法和geturi()方法是安全的了。
代码清单2-7给出了requestfacade类的定义。
注意requestfacade类的构造函数,它接受一个request对象,但立即将其赋给私有的servletrequest对象引用。还要注意的是,requestfacade中的每个方法会调用servletrequest对象中相对应的方法来执行。
responsefacade类的情况与此相同。
应用程序2中共需要使用6个类:
httpserver2
request
response
staticresourceprocessor
servletprocessor2
constants
httpserver2类与httpserver1类相似,只是在其await()方法中它会使用servletprocessor2类,而不是servletprocessor1类:
servletprocessor2类与servletprocessor1类相似,只是在其process()方法的以下部分中有些许不同:
运行应用程序
要在windows平台上运行该程序,可以在工作目录下执行如下命令:
在linux平台上,需要用冒号分割两个库文件:
可以使用与应用程序1相同的url来测试,结果是相同的。