Servlet体系结构

基础知识

Java Web应用是基于Servlet规范写的,而Servlet规范又是基于以下几个类运转的:

Servlet顶层类关联图:
在这里插入图片描述

从图中可以看到,有三个类ServletConfig、ServletRequest、ServletResponse是与Servlet主动关联的,而且这三个类都是通过容器传递给Servlet滴:

  • ServletConfig 是在 Servlet 初始化时就传给 Servlet 了
  • ServletRequest、ServletResponse用户请求达到后,调用 Servlet 时传递过来的。

补充一下知识:

Servlet 的运行模式是一个典型的握手型的交互式运行模式。

握手型的交互式就是两个模块为了交换数据通常都会准备一个交易环境,这个环境一直跟随个这个交易过程直到这个交易完成为止的方式。

对应到Servlet运行里面就是:

Servlet
交易地点
ServletContext
场景布置
ServletConfig
ServletRequest
ServletResponse

ServletConfig & ServletContext

首先你要知道,Servletxxx那都是接口,都是规范,实际运行的时候是要传对象的。

那么ServletConfig & ServletContext传给Servlet真正的对象是什么?

要回答这个问题,首先看他们俩在Tomcat容器的类关系图:

在这里插入图片描述

  • ServletConfig:

    其中StandardWrapperFacade 是 StandardWrapper 的门面类(参考门面设计模式),而且他们都实现了 ServletConfig 接口。也就是说,Servlet拿到的xxxConfig实际上是StandardWrapperFacade对象(facade——门面)

    StandardWrapperFacade能够保证从 StandardWrapper 中拿到 ServletConfig 所规定的数据,而又不把 ServletConfig 不关心的数据暴露给 Servlet,就很棒!这也是门面设计的目的——封装容器中的数据

  • ServletContext:

    同样的,Servlet拿到的xxxContext实际上是ApplicationContextFacade对象。

    (通过 ServletContext 可以拿到 Context 容器中一些必要信息,比如应用的工作路径,容器支持的 Servlet 最小版本等)

ServletRequest & ServletResponse

同样的问题,ServletRequest & ServletResponse传给Servlet真正的对象是什么?

我们自己通常使用的都是 HttpServletRequest 和 HttpServletResponse

在Tomcat容器的类关系图:
在这里插入图片描述

  • Tomcat 一接受到请求首先将会创建Request(org.apache.coyote.Request ) 和Response(org.apache.coyote.Response),

    ​ 这两个类是 Tomcat 内部使用的描述一次请求和相应的信息类它们是一个轻量级的类它们作用就是简单解析,将这个请求快速的分配给后续线程去处理,所以它们的对象很小,很容易被 JVM 回收。

  • 接下去Tomcat交给一个用户线程,请求开始被处理时,又创建Request(org.apache.catalina.connector.Request) 和 Response(org.apache.catalina.connector.Response) 对象。

    ​ 这两个对象一直贯穿整个 Servlet 容器直到要传给 Servlet。

    在路上的Request&Response
    在路上的Request&Response
    Servlet容器
    xxx操作
    Servlet

    ​ 当然,为了封装数据,最后传给 Servlet 的是门面类 RequestFacade 和 RequestFacade

看图理解:

转变过程
1
Http11Processor
2
Tomcat Container容器
3
Webapp Servlet
Socket
org.apache.coyote.Request
org.apache.coyote.Response
Connector
org.apache.catalina.connector.Request
org.apache.catalina.connector.Response
FilterChain
RequestFacade
ResponseFacade

这里的图只描述了传入,也就是刚刚讲的东西,当然还有传出,因此箭头应该是双向的。

Servlet工作方式

当用户从浏览器向服务器发起一个请求,通常会包含如下信息:http://hostname: port /contextpath/servletpath

现在知道这个URL对应的Servlet叫什么,那Tomcat是如何准确地将这个请求给工程中相应的Servlet呢?

  1. Tomcat7.0 中,这种映射工作有专门一个类来完成的,这个就是Mapper(org.apache.tomcat.util.http.Mapper) (这个类保存了 Tomcat 的 Container 容器中的所有子容器的信息)

  2. Request(org.apache.catalina.connector.Request) 类在进入 Container 容器之前(上面图有画),Mapper 会根据这次请求的 hostname 和 contextpath ,将 host 和Context 容器设置到 Request.mappingData 属性中。

    所以当 Request 进入 Container 容器之前,它要访问那个子容器这时就已经确定了。

    图解一波:

    进入Container容器前
    hostname+contextpath
    host+Context容器
    URL
    Mapper
    找到相应的host+Context容器
    设置到Request.mappingData
    确定了访问的子容器
    Request 的 Mapper 类关系图:

在这里插入图片描述

注意到MapperListener类,我们会发现在9.1中讲到Tomcat启动过程时的第19步就是这个:

在这里插入图片描述
这是 MapperListener 的 init 方法

public void init() { 
	    //不重要的
       findDefaultHost(); 
       Engine engine = (Engine) connector.getService().getContainer(); 
       engine.addContainerListener(this); 
       Container[] conHosts = engine.findChildren(); 
    
    	//将host及下面的子容器注册到中,只要容器有变,就会被通知,MapperListener.mapper属性也会随即被修改
       for (Container conHost : conHosts) { 
           Host host = (Host) conHost; //虽然是host类,但还是看做Container容器理解
           if (!LifecycleState.NEW.equals(host.getState())) { 
               //互相添加对方
               host.addLifecycleListener(this); //host加入this监听器
               registerHost(host);//注册host到this这里
           } 
       } 
}

和前面整合一下,看看Request请求是如何到达Wrapper来处理的(为了方便理解:Wrapper≈Servlet):

(疑难词:valve——n. 阀;真空管;活门)

Wrapper容器
Context容器
Host容器
Engine容器
Request类
StandardWrapperValve类
StandardContextValve类
StandardHostValve类
StandardEngineValve类
MappingData属性
用户的HTTP请求
Wrapper容器
Context容器
Host容器
Engine容器
容器改变
容器改变
容器改变
容器改变
StandardWrapperValve类
StandardContextValve类
StandardHostValve类
StandardEngineValve类
MapperListener类
MapperListener类
Request类
传入host+URL
设置这次请求的容器路径
Mapper
MappingData属性

到达之后,就是大家都知道的,执行Servlet.Service()方法,就开始我们的工作啦!

至此,我们鱼塘里的鱼儿(Servlet)终于动起来啦!

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐