Tomcat05——请求处理流程

1. 请求流程

        设计了这么多层次的容器,tomcat是怎么确定每一个请求应该由哪个Wrapper容器里的servlet来处理了?tomcat是用Mapper组件来完成这个任务的。

        Mapper组件的功能就是将用户的请求URL定位到一个Servlet,它的工作原理是:Mapper组件里保存了Web应用的配置信息,其实就是容器组件与访问路径的映射关系,比如Host容器配置的域名、Context容器配置的Web应用路径以及Wrapper容器里Servlet映射的路径,可以将这些配置信息理解成一个多层次的Map。

        当一个请求到来的时候,Mapper组件通过解析请求URL里的域名和路径,再到自己保存的Map里去查找,就能定位到一个Servlet。值得注意的是,一个请求URL只会定位到一个Wrapper容器,也就是一个Servlet。

1.1 从应用层面解析请求流程

用户在浏览器输入网址:http://localhost:8080/servlet_demo01/bbs/findAll 在tomcat中的请求流程

1. 请求经过Connector连接器

在server.xml的配置文件中,有一个connector是监听8080端口的

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

2. Connector在去找到对应的Service/Engine

在connector下面有一个引擎的配置,该引擎有一个默认的主机地址

<Engine name="Catalina" defaultHost="localhost">

该localhost指的就是Host节点 的name属性值。

3. 引擎在去找Host,一个引擎下是可以配置多个Host的。Host就相当于是一个虚拟的站点,我们可以在配置Host的时候,来配置主机的地址。

 <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

4. 在Host中配置了appBase的路径,然后就会去到webapps当中去查找请求路径下的名为servlet_demo01(Context)的应用

5. 定位了具体的应用之后,在根据后面的路径/bbs/findAll(Wrapper),到web.xml中的配置,定位到具体的Servlet

1.2 时序图解析请求流程

1. Connector组件Endpoint中的Acceptor监听客户端套接字连接并接收Socket

2. 将连接交给线程池Executor处理,开始执行请求响应任务。

3. processor组件读取消息报文,解析请求行,请求体、请求头,封装成Request对象

4. Mapper组件根据请求行的URL值和请求头的Host值匹配由哪个Host容器、Context容器、Wrapper容器处理请求

5. coyoteAdaptor组件负责将Connector组件和Engine容器关联起来,把生成的Request对象和响应对象Response传递到Engine容器中,调用Pipeline。

6. Engine容器的管道开始处理,管道中包含若干个value,每个value负责部分处理逻辑,执行完value后会执行基础的value--StandardEngineValue,负责调用Host容器的Pipeline

7. Host容器的管道开始处理,流程类似,最后执行Connector容器的Pipeline

8. Connector容器的管道开始处理,流程类似,最后执行Wrapper容器的Pipeline

9. Wrapper容器的管道开始处理,流程类似,最后执行Wrapper容器对应的Servlet对象的处理方法。

1.3 从源码层面解析请求流程

我们需要将我们的项目部署到源码上,这样才能debug访问到tomcat的源码,那么要如何才能部署到源码tomcat中了?

如图:只需要将我们的项目复制到源码包下的home/webapps下

然后,找到BootStrap,以debug模式重启tomcat源码程序。

注意:用火狐浏览器,因为用谷歌浏览器请求一次会发送两次http请求,一次是请求资源,一次是请求网站图标的,这样不利于我们跟踪流程。

请求流程图示:

1. 在浏览器输入连接,回车之后,程序首先经过NioEndpoind,接收浏览器的请求

2. 接收到请求之后,进行请求的处理

3. 然后将连接交给线程池Executor处理,开始执行请求响应任务

3.1 获取Processor对象

3.2 然后调用Processor的process方法

4. 将浏览器的请求解析成Request与Response对象

 5. 解析完成之后,调用adaptor对象中的service方法,将request与response对象传递过去

这个是adaptor就是coyoteAdaptor

6. 调用容器并执行

7. 进入StandardEngineValve,拿到Host主机

8. host再获取管道,调用StandardHostValve

9. 进去StandardHostValve,拿到Context

10. context再获取管道,调用StandardContextValve

11. 进去StandardContextValve,拿到Wrapper,并获取管道,调用StandardWrapperValve

12. 然后在StandardWrapperValve中有Servlet的初始化与赋值

 

因为,Wrapper中封装的就是Servlet

13. 接着将Servlet封装到过滤器类中

14. 执行过滤器

15. 执行Servlet的service方法

注意:这里的servlet就是请求的Servlet对象

总结:

        tomcat中的各个组件各司其职,组件之间松耦合,确保了整体架构的可伸缩性和可扩展性,那么在组件内部,如何增强组件的灵活性和扩展性了?在tomcat中,每个Catalina组件采用责任链来完成具体的请求处理。

        在Tomcat中定了Pipeline和Valve两个接口,Pipeline用于构建责任链,后者代表责任链上的每个处理器,Pipeline中维护了一个基础的Valve,它始终位于Pipeline的末端(最后执行),封装了具体的请求处理和输出响应的过程。当然,我们也可以调用addValve()方法,为Pipeline添加其他的Valve,后添加的Valve位于基础的Valve之前,并按照添加顺序执行。Pipeline通过获取首个Valve来启动整个链条的执行。

      tomcat的请求可以解析为两部分,一部分是Connector的请求解析,交给CoyoteAdaptor,将路径映射,在交给后面的Catalina容器去处理。

发布了128 篇原创文章 · 获赞 6 · 访问量 3207

猜你喜欢

转载自blog.csdn.net/weixin_43318134/article/details/103944695