关于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. protected Pipeline pipeline = new StandardPipeline(this);
  3. public StandardHost() {
  4. super();
  5. pipeline.setBasic(new StandardHostValve());
  6. }
  7. }

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. protected Valve first = null;
  3. public void addValve(Valve valve) {
  4. // Validate that we can add this Valve
  5. if (valve instanceof Contained)
  6. ((Contained) valve).setContainer(this.container);
  7. // Start the new component if necessary
  8. if (started) {
  9. if (valve instanceof Lifecycle) {
  10. try {
  11. ((Lifecycle) valve).start();
  12. } catch (LifecycleException e) {
  13. log.error("StandardPipeline.addValve: start: ", e);
  14. }
  15. }
  16. // Register the newly added valve
  17. registerValve(valve);
  18. }
  19. // 将配置的valve添加到链表中,并且每个容器的标准valve在链表的尾端
  20. if (first == null) {
  21. first = valve;
  22. valve.setNext(basic);
  23. } else {
  24. Valve current = first;
  25. while (current != null) {
  26. if (current.getNext() == basic) {
  27. current.setNext(valve);
  28. valve.setNext(basic);
  29. break;
  30. }
  31. current = current.getNext();
  32. }
  33. }
  34. }
  35. }

从上面可以清楚的看出,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

 
 
 

一件事,不管有多难,会不会有结果,这都不重要,即使失败了也无可厚非,关键是你有没有勇气解脱束缚的手脚,有没有胆量勇敢地面对。很多时候,我们不缺方
法,缺的是一往无前的决心和魄力。不要在事情开始的时候畏首畏尾,不要在事情进行的时候瞻前顾后,唯有如此,一切才皆有可能。

最新文章

  1. libevent源码分析:time-test例子
  2. 13. 星际争霸之php设计模式--正面模式
  3. JS,Jquery获取各种屏幕的宽度和高度
  4. error while loading shared libraries: xxx.so.x&quot; 错误的原因和解决办法
  5. shell 判断文件、目录是否存在
  6. WPF画N角芒星,正N角星
  7. 引入css外部样式表
  8. 大数据之scala基本语法学习
  9. int与string转换
  10. git常用命令一、git cherry-pick
  11. win10系统电脑无法识别u盘的解决办法
  12. Web 端异步下载文件
  13. nigix反向代理
  14. python网络之web框架
  15. docker安装elasticsearch及head插件
  16. webpack4 系列教程(十四):Clean Plugin and Watch Mode
  17. 使用git将本地项目推送到码云私有仓库
  18. Confluence 6 选择一个外部数据库
  19. 使用WPF Animated GIF实现GIF图片的播放
  20. WIN7系统 如何上传文件到FTP服务器中

热门文章

  1. Js中,Map对象的使用
  2. 【Jmeter自学】Linux环境下Jmeter运行
  3. 剑指Offer(三):从尾到头打印链表
  4. django-chunks文件
  5. Xshell 本地上传、远程下载文件
  6. 《算法》第三章部分程序 part 3
  7. 4. easyui删除功能实例
  8. PostgreSQL pg_dump&amp;psql 数据的备份与恢复
  9. tar 排除文件
  10. day20-面向对象编程、继承