Java Web应用是基于Servlet规范运转的,那么Servlet本身又是如何运转的?为何要设计这样的体系结构呢?Servlet顶层类的关系图如下图所示。
Servlet规范就是基于上图这几个类运转的,与Servlet主动关联的是三个类,分别是ServletConfig、ServletRequest、ServletResponse。这三个类都是通过容器传递给Servlet的,其中ServletConfig在Servlet初始化时就传给Servlet了,而后两个是在请求到达时调用Servlet传递过来的。我们很清楚ServeltRequest和ServletResponse在Servlet运行时的意义,但是ServletConfig和ServletContext对Servlet有何价值?仔细看看ServletConfig接口中生命的方法就会发现,这些方法都是为了获取这个Servlet的一些配置属性,而这些配置属性可能在Servlet运行时被用到。ServletContext又是干什么的呢?Servlet的运行模式是一个典型的“握手型的交互式”的运行模式。所谓“握手型的交互式”就是两个模块为了交换数据通常都会准备一个交易场景,这个场景一直跟随这个交易过程知道这个交易完成为止。这个交易场景的初始化是根据这次交易对象制定的参数来定制的,这些制定指定参数通常就是一个配置类。所以对号入座,交易场景就由ServletContext来描述,而定制的参数集合就由ServletConfig来描述,而ServletRequest和ServletResponse就是要交互的具体对象,它们通常都作为运输工具传递交互结果。
StandardWrapper和StandardWrapperFacade都实现了ServletConfig接口,而StandardWrapperFacade是StandardWrapper的门面类。所以传给Servlet的是StandardWrapperFacade对象,这个类能够保证从StandardWrapper中拿到ServletConfig所规定的数据,而又不把ServletConfig不关心的数据暴露给Servlet。
而ServletContext也与ServletConfig有类似的结构,在Servlet中能拿到的ServletContext的实际对象也是ApplicationContextFacade对象。ApplicationContextFacade同样保证ServletContext只能从容器中拿到它该拿的数据,它们都起到对数据的封装作用,它们使用的都是门面设计模式。
通过ServletContext可以拿到Context容器中的一些必要信息,如应用的工作路径、容器支持的Servlet最小版本等等。
在Servlet中定义的两个ServletRequest和ServletResponse实际的对象又是什么呢?我们在常见自己的Serlvet类时通常使用的都是HttpServletRequest和HttpServletResponse,它们继承了ServletRequest和ServletResponse。
Tomcat接到请求首先将会创建org.apache.coyote.Request和org.apache.coyote.Response,这两个类是Tomcat内部使用的描述一次请求和相应的信息类,他们是一个轻量级的类,作用就是在服务器接收到请求后,经过简单解析将这个请求快速分配给后续线程去处理,所以他们的对象很小,很容易被JVM回收。接下来当交给一个用户线程去处理这个请求时又创建org.apache.catalina.connector.Request和org.apache.catalina.connector.Response对象。这两个对象一直贯穿整个Servlet容器知道要传给Servlet,传给Servlet的是Request和Reponse的门面类RequestFacade和ResponseFacade。一次请求对应的Request和Response的类转化如下图所示。