Tomcat分析四 —— Pipeline-Valve管道阀门

​ 上一节讲了Container的创建过程,Container处理请求是使用Pipeline-valve管道处理的。下面先分析它的处理模式,然后分析实现方法

4.1 Pipeline-Valve处理模式

​ Pipeline-Valve是责任链模式,在一个请求处理过程中有多个处理者依次对请求进行处理。

​ Pipeline相当于处理请求的路线,Valve相当于每个处理者处理的过程

​ Pipeline-Valve的管道模型和普通的责任链模式有些不同,区别有两点:

  1. 每个Pipeline都有特定的Valve,且在管道的最后一个执行,这个Valve叫BaseValve,是不可删除的

  2. 上层容器的管道的BaseValve会调用下层容器的管道。4个容器的BaseValve分别是StandardEngineValve、StandardHostValve、StandardContextValve和StandardWrapperValve。处理流程如下

    ​ Filter中的FilterChain就是这种模式,FilterChain相当于Pipeline,每个Filter相当于一个Value,Servlet相当于对后的BaseValue

4.2 Pipeline-Valve的实现方法

​ Pipeline管道的实现分为生命周期管理和处理请求两部分

Pipeline管道生命周期的实现方法

​ Container中的Pipeline在抽象类ContainerBase中定义,并在生命周期的startInternal、stopInternal、destoryInternal方法中调用管道的相应生命周期方法(因为管道不需要初始化所以initInternal没有调用)

public abstract class ContainerBase extends LifecycleMBeanBase
        implements Container
protected synchronized void startInternal() throws LifecycleException {
		if (pipeline instanceof Lifecycle)
    		((Lifecycle) pipeline).start();
  
protected synchronized void stopInternal() throws LifecycleException {
          if (pipeline instanceof Lifecycle &&
                ((Lifecycle) pipeline).getState().isAvailable()) {
            ((Lifecycle) pipeline).stop();
        }
protected void destroyInternal() throws LifecycleException {
          if (pipeline instanceof Lifecycle) {
            ((Lifecycle) pipeline).destroy();
        }

​ Container的四个子容器都继承自ContainerBase,所以四个子容器在执行生命周期的方法时都会调用管道相应的生命周期方法

​ Pipeline使用的是StanardPipeline类型,里面的Valve保存在first属性中,Valve是链式结构,可以通过getNext方法一次获取每个Value,BaseValue单独保存在basic属性中(basic不能为空,在调用addValve方法添加Value时basic会同时保存到dirst的最后一个,如果没调用addValve方法first可能为空)。

​ StanardPipeline继承子LifecycleBase,实际处理生命周期的方法是startInternal、stopInternal和destoryInternel

public class StandardPipeline extends LifecycleBase implements Pipeline, Contained {
  protected synchronized void startInternal() throws LifecycleException {
    // 使用临时变量current遍历Value链里的所有Value,如果first为空则使用basic
    Valve current = first;
    if (current == null) {
      current = basic;
    }
    //遍历所有Value并调用start方法
    while (current != null) {
      if (current instanceof Lifecycle)
        ((Lifecycle) current).start();
      current = current.getNext();
    }
    //设置LifecycleState.STARTING状态
    setState(LifecycleState.STARTING);
  }
    protected synchronized void stopInternal() throws LifecycleException {
        setState(LifecycleState.STOPPING);
        Valve current = first;
        if (current == null) {
            current = basic;
        }
        while (current != null) {
            if (current instanceof Lifecycle)
                ((Lifecycle) current).stop();
            current = current.getNext();
        }
    }
		//删除所有的Valve
    protected void destroyInternal() {
        Valve[] valves = getValves();
        for (Valve valve : valves) {
            removeValve(valve);
        }
    }

​ getValves方法得到basic在内的所有Value集合

public Valve[] getValves() {
    ArrayList<Valve> valveList = new ArrayList<Valve>();
    Valve current = first;
    if (current == null) {
        current = basic;
    }
    while (current != null) {
        valveList.add(current);
        current = current.getNext();
    }
    return valveList.toArray(new Valve[0]);
}

Pipeline管道处理请求的实现方法

​ pipeline调用所包含Value的invoke方法处理请求,并在BaseValue里又调用了子容器pipeline所包含Value的invoke方法,直到最后调用了Wrapper的Pipeline所包含的BaseValue——StandardWrapperValve。

  • Connector接收到请求后调用最顶层容器的pipeline处理

  • 顶层容器的Pipeline处理后会在其BaseValue里调用下一层容器的pipeline进行处理,这样就可以 逐层调用所有容器的pipeline进行处理了。

    Engine的BaseValue是StandardEngineValve,它的invoke方法如下

    ​ 1. Host事先设置到request中,其他各层容器也会实现设置到request中

    ​ 2. 然后将请求传递到Host的管道

    ​ 3. Host的BaseValue也会调用Context的pipeline

    ​ 4. Context的BaseValue调用Wrapper的pipeline

    ​ 5. Wrapper的pipeline最后在其BaseValve(StandardWrapperValve)中创建FilterChain并调用其doFilter方法处理请求

    ​ 6. FilterChain包含我们配置的和请求相匹配的Filter和Servlet。它的doFilter方法会依次调用所有Filter的doFilter方法和Servlet的service方法,这样请求就得到了处理

    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        Host host = request.getHost();
        if (host == null) {
            response.sendError
                (HttpServletResponse.SC_BAD_REQUEST,
                 sm.getString("standardEngine.noHost", 
                              request.getServerName()));
            return;
        }
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(host.getPipeline().isAsyncSupported());
        }
        host.getPipeline().getFirst().invoke(request, response);
    }
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值