我们知道 Java Web 应用是基于 Servlet 规范运转的,那么 Servlet 本身又是如何运转的呢?为何要设计成这样呢
从上图可以看出 Servlet 规范就是基于这几个类运转的,与 Servlet 主动关联三个类 ServletConfig、 ServletRequest , ServletResponse
这三个类都是通过容器传递给 Servlet 的
- ServletConfig 在 Servlet 初始化时传给 Servlet
- 后两个在请求达到时调用 Servlet 时才传递
我们很清楚ServletRequest 和 ServletResponse 在 Servlet 运行时的意义,但是 ServletConfig 和 ServletContext 对 Servlet 有何价值?
- 仔细查看 ServletConfig 接口中声明的方法,发现都是为了获取这个 Servlet 的一些配置属性,而这些配置属性可能在 Servlet 运行时被用到。
- ServletContext 又是干什么的呢? Servlet 的运行模式是一个典型的“握手型的交互式”运行模式。
所谓“握手型的交互式”就是两个模块为了交换数据通常都会准备一个交易场景,这个场景一直跟随交易过程直到交易完成。这个交易场景的初始化是根据这次交易对象指定的参数来定制的,这些指定参数通常就会是一个配置类。所以对号入座,- 交易场景由 ServletContext 描述
- 定制的参数集合由 ServletConfig描述
- ServletRequest 和 ServletResponse 是要交互的具体对象,它们通常都是作为运输工具来传递交互结果
ServletConfig 是在 Servlet init 时由容器传过来的,那么 ServletConfig 到底是个什么对象呢?
可以看出 StandardWrapper 和 StandardWrapperFacade 都实现了 ServletConfig 接口,而 StandardWrapperFacade 是 StandardWrapper 门面类。
所以传给 Servlet 的是 StandardWrapperFacade 对象,它能够保证从 StandardWrapper 中拿到 ServletConfig 所规定的数据,而又不把 ServletConfig不关心的数据暴露给 Servlet
ServletContext 与 ServletConfig 也有类似的结构,Servlet 中能拿到的 ServletContext 的实际对象是 ApplicationContextFacade ApplicationContextFacade 同样保证 ServletContex只能从容器中拿到它该拿的数据,它们都起到对数据的封装作用,它们使用的都是门面设计模式
通过 ServletContext 可以拿到 Context 容器中一些必要信息,比如应用的工作路径,容器支持的 Servlet 最小版本等。
Servlet 中定义的两个 ServletRequest 和 ServletResponse 它们实际的对象又是什么呢?
我们在创建自己的 Servlet 类时通常使用的都是 HttpServletRequest 和 HttpServletResponse,它们继承了 ServletRequest 和** ServletResponse**
为何 Context 容器传过来的 ServletRequest、ServletResponse 可以被转化为 HttpServletRequest 和 HttpServletResponse 呢?
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 和 Response 的门面类 RequestFacade 和 ResponseFacade,这里使用门面模式与前面一样都是基于同样的目的即封装容器中的数据
一次请求对应的 Request 和 Response 的类转化如下图