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

    出处:http://gearever.iteye.com 

    关于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类为例: 

    Java代码
    public class StandardHost extends ContainerBase implements Host {   
      
      protected Pipeline pipeline = new StandardPipeline(this);   
      public StandardHost() {   
        super();   
        pipeline.setBasic(new StandardHostValve());   
      }   
      
    }

    Valve实现了具体业务逻辑单元。可以定制化valve(实现特定接口),然后配置在server.xml里。每层容器都可以配置相应的valve,当只在其作用域内有效。例如engine容器里的valve只对其包含的所有host里的应用有效。定制化的valve是可选的,但是每个容器有一个缺省的valve,例如engine的StandardEngineValve,是在StandardEngine里自带的,它主要实现了对其子host对象的StandardHostValve的调用,以此类推。 
    配置的例子有: 

    Xml代码
    <Engine name="Catalina" defaultHost="localhost">  
      <Valve className="MyValve0"/>  
      <Valve className="MyValve1"/>  
      <Valve className="MyValve2"/>  
       ……  
      <Host name="localhost"  appBase="webapps">  
      </Host>  
    </Engine>

    当在server.xml文件中配置了一个定制化valve时,会调用pipeline对象的addValve方法,将valve以链表方式组织起来,看一下代码; 

    Java代码
    public class StandardPipeline implements Pipeline, Contained, Lifecycle{   
      
      protected Valve first = null;   
      
      public void addValve(Valve valve) {   
      
        // Validate that we can add this Valve   
        if (valve instanceof Contained)   
           ((Contained) valve).setContainer(this.container);   
      
        // Start the new component if necessary   
        if (started) {   
           if (valve instanceof Lifecycle) {   
             try {   
               ((Lifecycle) valve).start();   
             } catch (LifecycleException e) {   
               log.error("StandardPipeline.addValve: start: ", e);   
             }   
           }   
           // Register the newly added valve   
           registerValve(valve);   
         }   
      
         // 将配置的valve添加到链表中,并且每个容器的标准valve在链表的尾端  
         if (first == null) {   
            first = valve;   
            valve.setNext(basic);   
         } else {   
            Valve current = first;   
            while (current != null) {   
              if (current.getNext() == basic) {   
                 current.setNext(valve);   
                 valve.setNext(basic);   
                 break;   
              }   
              current = current.getNext();   
            }   
         }  
      }   
    }

    从上面可以清楚的看出,valve按照容器作用域的配置顺序来组织valve,每个valve都设置了指向下一个valve的next引用。同时,每个容器缺省的标准valve都存在于valve链表尾端,这就意味着,在每个pipeline中,缺省的标准valve都是按顺序,最后被调用。 
    消息流 
    先看一下四大容器的标准valve的调用逻辑图。从中可以梳理出标准valve的逻辑。注意此图只是在缺省配置下的状态,也就是说每个pipeline只包含一个标准valve的情况。 
     
    图中显示的是各个容器默认的valve之间的实际调用情况。从StandardEngineValve开始,一直到StandardWrapperValve,完成整个消息处理过程。注意每一个上层的valve都是在调用下一层的valve返回后再返回的,这样每个上层valve不仅具有request对象,同时还能拿到response对象,想象一下,这样是不是可以批量的做很多东西?

  • 相关阅读:
    jQuery 基本选择器
    JavaScriptif while for switch流程控制 JS函数 内置对象
    JavaScrip基本语法
    数据库 存储引擎 表的操作 数值类型 时间类型 字符串类型 枚举集合 约束
    数据库基础知识 管理员 用户登录授权的操作
    粘包的产生原理 以及如何解决粘包问题
    socket TCP DPT 网络编程
    2018年年终总结
    Android技术分享
    No accelerator found
  • 原文地址:https://www.cnblogs.com/nizuimeiabc1/p/8934126.html
Copyright © 2011-2022 走看看