Tomcat的管道(Pipeline)机制以及Context,Wrapper容器

Posted 占用我名字

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tomcat的管道(Pipeline)机制以及Context,Wrapper容器相关的知识,希望对你有一定的参考价值。

最近学习了Tomcat,所以想把自己学到的东西总结记录一下,不紧是自己消化的过程,同时也希望帮助更多的人更好的去理解Tomcat的内部原理。因为博主看的是《深入剖析Tomcat》这本书,所以讲述的都以Tomcat4为标准,我认为理解了Tomcat4,后面的版本也会很容易去理解。

这次主要总结下Tomcat的管道(Pipeline)机制以及Context,Wrapper容器,其实tomcat简单的来说可以有两部分组成,一个就是连接器(Connector)和容器(container),如下图。连接器就是负责跟浏览器也就是客户端连接。容器也就是Servlet容器,用来负责跟Servlet有关的操作,Servlet也就是我们JAVA WEB中常常写的那个Servlet。因为这次主要总结的内容是跟容器有关,所以就简单的说一下连接器。

                                                                                      

1、连接器

连接器主要是负责跟浏览器建立连接,其实连接器的原理是Socket编程,Socket大家应该并不陌生。就是浏览器过来一个请求,就接收这个请求,然后连接器会分配一个线程去处理这个请求。因为tomcat是用java编写的,所以所谓的连接器就是一些JAVA类。大家对HTTP请求格式应该有所了解,如下图。

    

当在地址栏输入个地址,浏览器就以上面的格式向Tomcat发送信息,Tomcat的Socket是以String形式接收到上面的信息,然后连接器就开始创建Request,Response对象,接着解析上述的信息,也就是对一些字符串的操作。把解析到的数据放入request对象的变量中。当这些操作完毕后,就把Request跟Response对象传给容器。从连接器到容器的简单步骤就完成。


2、容器

 容器主要是用来负责调用Servlet,同时也有很多组件,例如载入器,主要是负责把这些Servlet先载入,到时候容器调用对应的Servlet的时候,直接从载入器取得。Tomcat中有四个容器,分别是Engine,Host,context,Wrapper。级别是从大到小的。context表示一个Web应用程序,Wrapper表示一个Servlet。一个Web应用程序中可能会有多个Servlet。Host代表的是一个虚拟主机,就好比你的一个Tomcat下面可能有多个Web应用程序。同时Engine是Host的父类,Host是Context的父类,Context是Wrapper父类。他们之间的关系如下图


每个容器都实现了Container接口,上图中的虚线表示implement,实线表示extends。我举一个简单的例子来说明下Context跟Wrapper的区别。

假如你有一个Web程序,其中有两个Servlet ,两个Servlet在web.xml配置文件中如下。


<?xml version="1.0"?>
<web-app     xmlns="http://xmlns.jcp.org/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee

http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd"

            version="3.0">

    <welcome-file-list>
        <welcome-file>/index.html</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>MyFirstServlet</servlet-name>
        <servlet-class>MyFirstServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyFirstServlet</servlet-name>
        <url-pattern>/MyFirstServlet</url-pattern>
    </servlet-mapping>
 </servlet>

  <servlet>
        <servlet-name>MySecondServlet</servlet-name>
        <servlet-class>MySecondServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MySecondServlet</servlet-name>
        <url-pattern>/MySecondServlet</url-pattern>
    </servlet-mapping>
 </servlet>
</web-app>
此时就会创建两个Wrapper,创建一个Context对象。类似于如下的代码:

Wrapper wrapper1 =new StandardWrapper();

wrapper1.setName("MyFirstServlet");   //上面配置文件中的<servlet-name>里面的内容

wrapper1.setServletClass("MyFirstServlet"); //上面配置文件<servlet-class>里面的内容

Wrapper wrapper2 =new StandardWrapper();

wrapper2.setName("MySecondServlet");

wrapper2.setServletClass("MySecondServlet");

Context context =new StandradContext();  //创建父类

context.addChild(wrapper1);

context.addChild(wrapper2);

context.addServletMapping("/MyFirstServlet","MyFirstServlet");   //第一个参数就是上面配置文件的<url-pattern>,第二个参数对应的是wrapper的名称

context.addServletMapping("/MySecondServlet","MySecondServlet");


假设你的一个请求为如下:http://localhost:8080/MyApp/MyFirstServlet     (其中MyApp为你的Web应用名)

Tomcat的连接器处理完这些请求后,会调用父容器context,同时把request,respone 传给context容器,容器根据你请求的URL,也就是/MyFirstServlet ,得到对应的Wrapper,Wrapper中又可以找到对应的ServletClass,然后通过这个名称在载入器中找到对应的Servlet类,然后调用Servlet的service方法。这就是大概的过程。接下来总结下Tomcat的管道机制。

  大家应该都知道java web 的过滤器,其实管道机制就类似于过滤器。当连接器处理完请求后开始调用容器,从容器的一系列处理到调用对应的Servlet之间,会调用管道机制处理一系列的请求。其实类似于如下图所示

                                                    

中间的那一部分就类似与管道,而管道中的每一个阀就是一个JAVA类,也就是容器到调用对应的Servlet过程中要进入这个管道,然后调用管道中的阀。管道中有一个基础阀,这个基础阀是在上面的所有阀调用完成以后再调用。其中就是基础阀跟Servlet进行连接,如果前面的阀只是对Requset进行一些处理的话,那么基础阀会根据请求的URL调用对应的Servlet的Service方法。

在前面讲第二小节刚开始给说了容器之间的UML类图,其实tomcat的四个容器都继承自ContainerBase。而ContainerBase这个类,实现了Pipeline这个借口。Pipeline就是管道。Pipeline的接口如下

public interface Pipeline

public Valve getBasic();                               //得到基础阀

public void setBasic(Valve valve);            //设置基础阀

public void addValve(Valve valve);           //增加阀

public Valve[] getValves(); //得到所有的阀(不包括基础阀)

public void invoke(Request request, Response response)
        throws IOException, ServletException;     //这个方法就是用来进行调用每个阀。

public void removeValve(Valve valve);


其实ContainerBase中还有一个变量如下

 protected Pipeline pipeline = new StandardPipeline(this);

StandardPipeline是Pipeline的实现类。 因为ContainerBase实现了Pipeline接口。所以ContainerBase会实现invoke方法。如下:

    public void invoke(Request request, Response response)
        throws IOException, ServletException


        pipeline.invoke(request, response);   //这个方法就是调用管道的invoke方法,然后开始处理管道中的一系列阀,最后处理基础阀。在基础阀中调用对应的Servlet.


   

从前面知道连接器处理完连接后,会调用Servlet容器。其实调用的就是Servlet容器的invoke方法,然后处理管道中的一系列阀,最后调用对应的Servlet.


本次主要总结了管道机制在一次请求的流程中是如何被应用到了,并没有更深的总结代码上面的东西,先了解下tomcat的运行机理,然后再看代码可能会更加容易一些。

这是博主第一次写博客,如果有些地方写的不够合理或者不对的地方,希望大家可以及时告诉我。总结的不是很好,希望大家笑纳。

以上是关于Tomcat的管道(Pipeline)机制以及Context,Wrapper容器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 GridSearchCV 比较多个模型以及 python 中的管道和超参数调整

Tomcat中管道

sklearn.pipeline.Pileline

TOMCAT8源码分析——处理请求分析(下)

Redis精通系列——Pipeline(管道)

redis管道命令pipeline的使用