Tomcat源码分析-请求流程(一)

调试分析

 

由于源码一步一步调试效率太低了,所以我这里就直接在自定义的Filter类上的doFilter方法中打上断点

先通过线程栈来大致看一下,请求的过程中执行了哪些步骤
每一个方法点进去,然后给它整理成一张表格,如下:
分析:
  • 上图执行执行次数最多的方法是invoke
  • 所有调用invoke方法的类都以Valve结尾
  • 调用invoke方法都是通过getNext和getFirst
 
第一步
 
首先从invoke方法执行多的地方开始,我们来分析一个Valve这个到底是什么东西?
通过上面,我们可以看出,调用invoke方法的所有的类,都是以Valve结尾的,说明这些类都有valve特征?那到底valve有什么特征呢?
Valve下面有一个ValveBase基类,所有的类都继承于该基类,并且Valve下面有两个重要的方法,getNext 和 invoke
public interface Valve {
    public Valve getNext();
    public void setNext(Valve valve);
    public void invoke(Request request, Response response) throws IOException, ServletException;
    // 省略其它...
}

 

根据类中的描述,valve所有的方法都和pipeline有关,那么pipeline到底是什么东西呢?
pipeline意为管道,valve为阀门,这两个东西当然密不可分了。但是还是不明白这两个东西是什么?具体有什么功能?
我们先来看一下Pipeline接口
public interface Pipeline {
    public Valve getBasic();
    public void setBasic(Valve valve);
    public void addValve(Valve valve);
    public Valve[] getValves();
    public void removeValve(Valve valve);
    public Valve getFirst();
    public boolean isAsyncSupported();
    public Container getContainer();
    public void setContainer(Container container);
}

既然有管道、有阀门,那是不是应该也有一个容器的东西,那这样一来就好理解了,每一个请求好比像是水,它想要进入到容器里是需要通过管道,然后经过阀门的层层过滤,最后到达容器。从这也体现了Tomcat的设计者们将现实生活中的实例引入到程序中的设计思想。

 
第二步
 
了解了valve这个是什么东西,我们接下来看看它底下是如何层层过滤的?
Valve过滤顺序从上至下
  1. StandardEngineValve
  2. AccessLogValve
  3. ErrorReportValve
  4. StandardHostValve
  5. NonLoginAuthenticator
  6. StandardContextValve
  7. StandardWrapperValve
从上面标红的几个关键字能看出什么来不?
依次向下传递:Engine --> Host --> Context --> Wrapper  这个是不是和我们的server.xml 文件Engine组件的层级关系一样的
即,当通过http请求 http://localhost:8080/jsp-web/test/1 访问tomcat的时候执行如下步骤:
  1. 通过localhost主机名称找到Host
  2. /jsp-web找到对应的Context
  3. 通过/test/1 找到对应的Wrapper,最终就能访问到你写的Filter
备注:上面的AccessLogValve,为访问日志,记录每次访问的url。
 
 
第三步
 
在Http11NioProcessor类中的process方法中,通过 getAdapter() 获得CoyoteAdapter对象,然后调用service方法
接下来我们来看一下CoyoteAdapter这个类是什么东西?coyote 是丛林狼的意思,为什么tomcat设计者要把这个命名为种动物的名称?
关于官网对coyote介绍:
Coyote HTTP / 1.1连接器元件代表一个支持HTTP / 1.1协议的连接器组件。除了执行servlet和JSP页面的功能外,它能够充当独立的Web服务器。该组件的特定实例侦听服务器上特定TCP端口号上的连接。可以将一个或多个此类连接器配置为单个服务的一部分,每个连接器都转发到关联的引擎以执行请求处理并创建响应。
  • CoyoteAdapter这个类位于org.apache.catalina.connector 包下
  • tomcat也有一个tomcat-coyote.jar
  • tomcat的Request有两个,一个是coyote包下的,另一个是connector包下的。getAdapter().service(request, response) 方法中request参数属于coyote包下的,它下一步要执行的invoke(request, response) 方法中request参数属于connector包下的
  • Http11NioProtocol 和 Http11NioProcessor 在tomcat-coyote.jar包下
从上面的几个特点得出结论:
  • CoyoteAdapter 与connector连接有关
  • CoyoteAdapter 是一个适配器
  • CoyoteAdapter 是tomcat-coyote框架的桥梁
 
 
总结
 
通过上面步骤,给它简单画了一个流程图:
Tomcat请求流程如下:
当用户发送HTTP请求http://localhost/context/wrapper/1 
  1. NioEndPoint接收到请求(执行其内部类SocketProcessor的run方法);
  2. Http11NioProtocol$Http11ConnectionHandler处理
  3. Http11NioProcessor处理
  4. CoyoteAdapter将coyote类型Request/Response转换成Servlet类型的Request/Response对象,把请求交给Pipeline管道
  5. Engine阀门开始处理,拿到对应的Host,开始将请求交给Host处理;
  6. Host阀门开始处理,拿到对应的Context,开始将请求交给Context处理;
  7. Context阀门开始处理,拿到对应的Wrapper,开始将请求交给Wrapper处理;
  8. Wrapper阀门开始处理,拿到对应的FilterChain,交给FilterChain处理;
  9. FilterChain中包含了一个过滤器filters的数组,从该数组中的第一个Filter开始依次执行(filters是在加载web.xml文件的时候设置进去的,这也是过滤器的执行顺序会按照web.xml配置的顺序的执行原因);
 
posted @ 2020-05-09 23:36  cao_xiaobo  阅读(645)  评论(0编辑  收藏  举报