zoukankan      html  css  js  c++  java
  • tomcat架构分析(valve机制)

    关于tomcat的内部逻辑单元的存储空间已经在相关容器类的blog里阐述了。在每个容器对象里面都有一个pipeline及valve模块。 它们是容器类必须具有的模块。在容器对象生成时自动产生。Pipeline就像是每个容器的逻辑总线。在pipeline上按照配置的顺序,加载各个 valve。通过pipeline完成各个valve之间的调用,各个valve实现具体的应用逻辑。
    先看一下pipeline及valve的逻辑概念图。

    这些valve就是在tomcat的server.xml中配置,只要满足一定条件,继承ValveBase基类
    引用
    org.apache.catalina.valves.ValveBase

    就可以在不同的容器中配置,然后在消息流中被逐一调用。每个容器的valve的作用域不一样,在总体结构中已有说明。这里红色标记的是配置的自定义的valve,这样可以扩展成多个其他应用,例如cluster应用等。
    Tomcat实现

    Tomcat提供了Pipeline的标准实现:
    引用
    org.apache.catalina.core.StandardPipeline


    四大容器类StandardEngine,StandardHost,StandardContext及StandardWrapper都有各自缺省的标准valve实现。它们分别是
    • Engine:org.apache.catalina.core.StandardEngineValve
    • Host: org.apache.catalina.core.StandardHostValve
    • Context:org.apache.catalina.core.StandardContextValve
    • Wrapper:org.apache.catalina.core.StandardWrapperValve

    容器类生成对象时,都会生成一个pipeline对象,同时,生成一个缺省的valve实现,并将这个标准的valve对象绑定在其pipeline对象上。以StandardHost类为例:
    1. public class StandardHost extends ContainerBase implements Host {   
    2.   
    3.   protected Pipeline pipeline = new StandardPipeline(this);   
    4.   public StandardHost() {   
    5.     super();   
    6.     pipeline.setBasic(new StandardHostValve());   
    7.   }   
    8.   
    9. }  

    Valve实现了具体业务逻辑单元。可以定制化valve(实现特定接口),然后配置在server.xml里。每层容器都可以配置相应的 valve,当只在其作用域内有效。例如engine容器里的valve只对其包含的所有host里的应用有效。定制化的valve是可选的,但是每个容 器有一个缺省的valve,例如engine的StandardEngineValve,是在StandardEngine里自带的,它主要实现了对其子 host对象的StandardHostValve的调用,以此类推。
    配置的例子有:
    1. <Engine name="Catalina" defaultHost="localhost">  
    2.   <Valve className="MyValve0"/>  
    3.   <Valve className="MyValve1"/>  
    4.   <Valve className="MyValve2"/>  
    5.    ……  
    6.   <Host name="localhost"  appBase="webapps">  
    7.   </Host>  
    8. </Engine>  

    当在server.xml文件中配置了一个定制化valve时,会调用pipeline对象的addValve方法,将valve以链表方式组织起来,看一下代码;
    1. public class StandardPipeline implements Pipeline, Contained, Lifecycle{   
    2.   
    3.   protected Valve first = null;   
    4.   
    5.   public void addValve(Valve valve) {   
    6.   
    7.     // Validate that we can add this Valve   
    8.     if (valve instanceof Contained)   
    9.        ((Contained) valve).setContainer(this.container);   
    10.   
    11.     // Start the new component if necessary   
    12.     if (started) {   
    13.        if (valve instanceof Lifecycle) {   
    14.          try {   
    15.            ((Lifecycle) valve).start();   
    16.          } catch (LifecycleException e) {   
    17.            log.error("StandardPipeline.addValve: start: ", e);   
    18.          }   
    19.        }   
    20.        // Register the newly added valve   
    21.        registerValve(valve);   
    22.      }   
    23.   
    24.      // 将配置的valve添加到链表中,并且每个容器的标准valve在链表的尾端  
    25.      if (first == null) {   
    26.         first = valve;   
    27.         valve.setNext(basic);   
    28.      } else {   
    29.         Valve current = first;   
    30.         while (current != null) {   
    31.           if (current.getNext() == basic) {   
    32.              current.setNext(valve);   
    33.              valve.setNext(basic);   
    34.              break;   
    35.           }   
    36.           current = current.getNext();   
    37.         }   
    38.      }  
    39.   }   
    40. }  

    从上面可以清楚的看出,valve按照容器作用域的配置顺序来组织valve,每个valve都设置了指向下一个valve的next引用。同 时,每个容器缺省的标准valve都存在于valve链表尾端,这就意味着,在每个pipeline中,缺省的标准valve都是按顺序,最后被调用。
    消息流
    先看一下四大容器的标准valve的调用逻辑图。从中可以梳理出标准valve的逻辑。注意此图只是在缺省配置下的状态,也就是说每个pipeline只包含一个标准valve的情况。

    图中显示的是各个容器默认的valve之间的实际调用情况。从StandardEngineValve开始,一直到 StandardWrapperValve,完成整个消息处理过程。注意每一个上层的valve都是在调用下一层的valve返回后再返回的,这样每个上 层valve不仅具有request对象,同时还能拿到response对象,想象一下,这样是不是可以批量的做很多东西?
     
    有人问?  :  valve消息流中说的是每层只有一个valve的调用情况。如果每层有多个valve的情况下,消息流又是怎样的呢?
     
    回 答  :          每一层有多个valve,以Engine层为例, 都是以这个顺序 valve0,valve1,...StandardEngineValve进行调用,典型的责任链模式,各个valve之间根据一定的逻辑通过 getNext().invoke(request, response);调用下一个valve

     
     
     
    做 一件事,不管有多难,会不会有结果,这都不重要,即使失败了也无可厚非,关键是你有没有勇气解脱束缚的手脚,有没有胆量勇敢地面对。很多时候,我们不缺方 法,缺的是一往无前的决心和魄力。不要在事情开始的时候畏首畏尾,不要在事情进行的时候瞻前顾后,唯有如此,一切才皆有可能。
  • 相关阅读:
    不同Activity之间传递线程
    面向对象编程笔记--static
    SQL Server Compact/SQLite Toolbox 使用
    VirtualBox 磁盘容量调整
    scala快速入门
    Microsoft.Xna.Framework.TitleContainer.OpenStream()
    Windows Phone 7 中拷贝文件到独立存储
    Windows Phone 7 上传图片
    JavaScript 中undefined,null,NaN的区别
    CentOS7攻克日记(三) —— 安装Python3.6
  • 原文地址:https://www.cnblogs.com/bolang100/p/6041426.html
Copyright © 2011-2022 走看看