本篇我们将来分析一下Tomcat中所涉及到设计模式,本文我们将主要来分析 外观模式观察者模式责任链模式模板方法模式 , 命令模式

在开始本文之前,笔者先说明一下对于设计模式的一点看法。笔者曾经经常看到网上有人讨论设计模式,也偶尔会遇到有人非要严格按照GOF设计模式的类图以及其中的角色去套用别人的设计,只要类图不一样,或者角色多了或者少了就会觉得怎么和官方定义的模式不一样,其实这都是对设计模式的误解。设计模式其实不仅仅存在软件行业,各行各业其实都有模式,它是所在行业对一些通用问题解决方案的总结和抽象,是一种对常见问题的抽象的解决方案,不是一种具体的实现,所以我们在讨论设计模式的时候,千万别一个劲的套用GOF设计模式中的类图以及其中所涉及到的角色,而是要理解设计模式的思维,理解设计模式的使用场景,只有理解了设计模式中所蕴含的思维以及具体的使用场景以后,你才算是真正的掌握了它。ok,小扯了一下淡,接下来我们进入主题吧。

外观模式

定义

外观模式封装了子系统的具体实现,提供统一的外观类给外部系统,这样当子系统内部实现发生变化的时候,不会影响到外部系统。

外观模式在Tomcat的应用

在Tomcat中对于Request,Response,StandardSession,ApplicationContext,StandardWrapper都采用了外观模式,它的类图如下:

通过上图,我们可以看到RequestFacade包装了Request,它们都实现了HttpServletRequest,当传递Request对象给应用的时候,其实是返回了RequestFacade对象,而RequestFacade内部可以根据是否自定义了安全管理器来进行相应的操作。

对于Response,StandardSession等处理是类似的,这里就不赘述了。

观察者模式

定义

观察者模式是一种非常常用的模式,比如大家熟悉的发布-订阅模式,客户端应用中的事件监听器,以及通知等其实都属于观察者模式。观察者模式主要是在当系统中发生某个状态变更或者事件的时候,有另外一些组件或者对象对此次变化有兴趣,这个时候那些对变化感兴趣的对象就可以做为观察者对象来监听变化,而被观察对象要负责发生变化的时候触发通知操作。

观察者模式在Tomcat的应用

Tomcat中需要对很多组件进行生命周期管理,为此Tomcat抽象了统一的生命周期管理骨架,通过这个骨架将所有需要进行生命周期管理的类都纳入进来管理,而这里的骨架的类图如下:

通过上图我们可以看出Tomcat抽象了一个LifecycleSupport的类,而所有需要生命周期管理的组件通过LifecycleSupport类通知对某个生命周期事件感兴趣的观察者,而所有的观察者都需要实现LifecycleListener。
另外我们需要关注一下EventObject对象,它里面定义了一个事件源对象,所谓事件源就是事件发生的地方,而在Tomcat的设计中,事件源就是实现了LifeCycle接口的各个需要管理生命周期的组件,这里LifecycleSupport和LifeCycleBase之间是双向的关联,LifeCycleSupport关联LifeCycle对象就是为了实现事件源的传递,这样在LifeCycleSupport触发事件的时候,可以通过事件源构建EventObject.这样以来LifecycleListener就可以通过事件对象获取到事件源,从而做一些与事件源相关的操作。

责任链模式

定义

通过名称我们应该就能知道责任链模式是解决啥问题的?当我们系统在处理某个请求的时候,请求需要经过很多个节点进行处理,每个节点只关注自己的应该做的工作,做完自己的工作以后,将工作转给下一个节点进行处理,直到所有节点都处理完毕。责任链模式在日常生活中例子挺多,比如快递,当你发一个从深圳到北京的快递的时候,你的包裹会从一个分拨中心传递到下一个分拨中心,直到目的地,这里面每个分拨中心都是链路上的一个节点,它做完自己的工作,然后将工作传递到下一个节点,还比如路由器中传递某个数据包其实也是同样的思路。

责任链模式在Tomcat的应用

Tomcat中请求的处理流程其实就是采用了责任链模式,关于Tomcat请求处理,大家可以参考下Tomcat请求处理流程(Tomcat源代码阅读系列之五),Tomcat中责任链模式的实现的类图如下图所示:

从上图中,我们可以看到每一个容器都会有一个Pipeline,而一个Pipeline又会具有多个Valve阀门,其中StandardEngine对应的阀门是StandardEngineValve,StandardHost对应的阀门是StandardHostValve,StandardContext对应的阀门是StandardContextValve,StandardWrapper对应的阀门是StandardWrapperValve。这里每一Pipeline就好比一个管道,而每一Valve就相当于一个阀门,一个管道可以有多个阀门,而对于阀门来说有两种,一种阀门在处理完自己的事情以后,只需要将工作委托给下一个和自己在同一管道的阀门即可,第二种阀门是负责衔接各个管道的,它负责将请求传递给下个管道的第一个阀门处理,而这种阀门叫Basic阀门,它是每个管道中最后一个阀门,上面的Standard*Valve都属于第二种阀门。我们可以形象的通过下图来描述上面的过程:

通过上图,我们可以很清楚的了解到Tomcat的请求处理流程。当用户请求服务器的时候,Connector会接受请求,从Socket连接中根据http协议解析出对应的数据,构造Request和Response对象,然后传递给后面的容器处理,顶层容器是StandardEngine,StandardEngine处理请求其实是通过容器的Pipeline进行的,而Pipeline其实最终是通过管道上的各个阀门进行的,当请求到达StandardEngineValve的时候,此阀门会将请求转发给对应StandardHost的Pipeline的第一个阀门处理,然后以此最终到达StandardHostValve阀门,它又会将请求转发给StandardContext的Pipeline的第一个阀门,这样以此类推,最后到达StandardWrapperValve,此阀门会根据Request来构建对应的Servelt,并将请求转发给对应的HttpServlet处理。从这里我们可以看出其实Tomcat核心处理流程就是通过责任链一步步的组装起来的。

模板方法模式

定义

模板方法模式抽象出某个业务操作公共的流程,将流程分为几个步骤,其中有一些步骤是固定不变的,有一些步骤是变化的,固定不变的步骤通过一个基类来实现,而变化的部分通过钩子方法让子类去实现,这样就实现了对系统中流程的统一化规范化管理。在日常生活中其实也有类似的例子,比如我们知道的连锁加盟店,他们都是有固定的加盟流程,只不过每一家店开的时候,店的选址,装修等不同的而已,但是总体的加盟流程已经是确定的。

模板方法模式在Tomcat的应用

Tomcat中关于生命周期管理的地方很好应用了模板方法模式,在一个组件的生命周期中都会涉及到init(初始化),start(启动),stop(停止),destory(销毁),而对于每一个生命周期阶段其实都有固定一些事情要做,比如判断前置状态,设置后置状态,以及通知状态变更事件的监听者等,而这些工作其实是可以固化的,所以Tomcat中就将每个生命周期阶段公共的部分固化,然后通过initInternal,startInternal,stopInternal,destoryInternal这几个钩子方法开放给子类去实现具体的逻辑。Tomcat中关于模板方法模式的实现如下图所示:

命令模式

定义

命令模式将请求封装为一个命令,将命令发送者和命令接受者解耦,并且所有命令对客户端来说都有统一的调用接口,使用命令模式还可以支持命令的撤销操作,在很多GUI程序中大量使用了此模式。
接下来我们来说一个场景大家感受下,我们有时候可能会遇到接口方法参数过多的问题,这样的接口不仅看起来丑陋而且不方便阅读,对客户端不友好。遇到这种情况我们可能选择将各种参数打包为一个参数对象,接口只需要一个参数对象即可,但是在具体的接口实现中,我们又要做条件判断根据参数值的不同做出不同的响应操作,这个时候其实就可以考虑将不同的逻辑实现和各种参数通过命令打包,然后提供一个命令工厂,客户端通过工厂生产出命令,然后直接调用即可。
其实在日常生活中,命令模式也很常见,比如公司老大给你分配了个任务,让你去做,他可能不关心你具体怎么做的,你做完了以后告诉他结果即可。

命令模式在Tomcat的应用

命令模式在Tomcat中主要是应用在对请求的处理过程中,Tomcat的实现中,根据它支持两种协议AJP和Http,而在具体的IO实现中,又分为Java同步阻赛IO,Java同步非祖塞IO,以及采用APRApache Portable Runtime 支持库,因此Tomcat统一了org.apache.coyote.Processor接口,根据协议和IO实现的不同通过不同的Process子类去实现,Connector作为客户端每次只需要根据具体的协议和IO实现创建对应的Process执行即可。下面我们来看一下命令模式在Tomcat中实现的相关类图:

通过上图我们可以清楚的看到,Tomcat首先根据协议的不同将Processor分为了Ajp和Http两组,然后又根据具体的IO实现方式的不同,将每一组都会实现同步祖塞IO,同步非祖塞IO,以及APR的Processor。 接下来我们再来看一个类图,我们就可以更加清楚的看到Tomcat中是如何利用命令模式来根据不同的协议以及IO实现方式来处理请求的。我们来看一下Tomcat中关于ProtocolHandler的类图。

通过上图我们可以看到针对每一种协议和IO实现方式的组合,都会有相应的协议处理类,而每个协议处理类都会有一个Handler,而每一个Handler在运行的时候就会创建出对应的Processor,比如AjpProtocol.AjpConnectionHandler创建AjpProcessor处理器,其它的类似。

通过上面的描述,我们可以看出Tomcat接受请求的处理流程如下:
Connector通过对应的Endpint监听Socket连接,当对应的端口有连接进来的时候,对应的Endpoint就会通过对应的Handler类处理,而Handler处理的时候,又会创建对应的Processor处理,而对应的Processor命令对象会解析Socket流的数据,然后生成Request和Response对象,最终通过上面说的责任链模式一步步的通过各个容器。

Tomcat源代码阅读系列之八:Tomcat 设计模式总结相关推荐

  1. 【转】Tomcat总体结构(Tomcat源代码阅读系列之二)

    本文是Tomcat源代码阅读系列的第二篇文章,我们在本系列的第一篇文章:在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码一文中介绍了如何在intelliJ IDEA 和 Ec ...

  2. Tomcat源代码解析系列

    学web也有一段时间了.为了从底层了解web应用在Tomcat中的执行,决定看一下Tomcat的源代码參见<How Tomcat works>    和大牛博客.对大体架构有了一定的了解, ...

  3. 说说Javaweb 服务器与Tomcat源代码解析

    Tomcat 源代码(GitHub) Javaweb 服务器机制: servlet 是javaweb的请求和响应的出入口,所以javaweb开发必定基于支持servlet,或者有servlet容器,如 ...

  4. 死磕Tomcat系列(6)——Tomcat如何做到热加载和热部署的

    死磕Tomcat系列(6)--Tomcat如何做到热加载和热部署的 热部署就是在服务器运行时重新部署项目,热加载即在在运行时重新加载class,从而升级应用. 通常情况下在开发环境中我们使用的是热加载 ...

  5. Tomcat系列(6)——Tomcat处理一个HTTP请求的过程

    Tomcat的架构图   图三:Tomcat Server处理一个HTTP请求的过程 处理HTTP请求过程 假设来自客户的请求为:http://localhost:8080/test/index.js ...

  6. Tomcat系列(5)——Tomcat配置详细部分

    Tomcat的架构图 Tomcat的组织结构 Tomcat是一个基于组件的服务器,它的构成组件都是可配置的,其中最外层的是Catalina servlet容器,其他组件按照一定的格式要求配置在这个顶层 ...

  7. tomcat宕机自动重启和每日定时启动tomcat【工具包系列】

    在项目后期维护中会遇到这样的情况,tomcat在内存溢出的时候就出现死机的情况和遇到长时间不响应,需要人工手动关闭和重启服务,针对这样的突发情况,希望程序能自动处理问题而不需要人工关于,所以才有了目前 ...

  8. Linux 配置系列 三 tomcat

    一.环境准备 JDK版本: jdk1.8: 操作系统: centos 7.6 : tomcat: apache-tomcat-8.5.5; 前提条件: 运行Tomcat必须先安装jdk 二.配置tom ...

  9. [置顶] 为什么要阅读源代码?如何有效的阅读源代码? 选一些比较优秀的开源产品作为源代码阅读对象?...

    盛大TeamHost上有个关于学习开源项目的wiki :http://www.teamhost.org/projects/learn-with-open-source/wiki/Wiki 一.为什么要 ...

最新文章

  1. LeetCode简单题之反转字符串
  2. python使用fpdf生成pdf章节(chapter)文件包含:页眉、页脚、章节主体、章节内容等;
  3. Python 字符串操作
  4. 搭建Nginx+Tomcat 负载均衡集群
  5. 在AWS控制台里创建key Pair
  6. 215.数组中的第K个最大元素/347. 前 K 个高频元素
  7. Java原生API操作XML
  8. mysql排插问题_手把手教你分析 MySQL 死锁问题
  9. Output error file to the following location:[ A:\GHOST ERR.TXT] 错误处理
  10. ModBus通信协议的【Modbus RTU 协议使用汇总】
  11. 134. PHP 工具
  12. js获取chrome浏览器版本信息
  13. Java程序设计基础——cmd编译运行java文件详细步骤
  14. Web测试和App测试区别
  15. 新一配:为什么现在都找不到破解软件了?
  16. 小米手机android程序闪退,告诉大家小米手机应用闪退的解决方法,不需要修复...
  17. 基于Java的图书管理系统(附源码和课件)
  18. java时区_Java时区的转换
  19. java中bean是什么_java中bean是什么意思?
  20. python错误:TypeError: Cannot interpret ‘3‘ as a data type

热门文章

  1. Apache网页优化概述
  2. Linux中常见服务对应的端口号
  3. shell脚本详解(四)——循环语句之while循环和until循环(附加例题及解析)
  4. 中标麒麟linux系统忘记root密码,中标麒麟(龙芯CPU)--忘记root密码怎么修改?
  5. ale插件 vim_Vim之代码异步检测插件 ALE -- 实时检查verilog等代码的正确性
  6. vs code 开发企业级python_基于VS Code配置Python开发环境
  7. 微信支付宝服务器在哪里,支付宝支付与微信支付服务端回调notify_url数据的区别...
  8. 新疆计算机一级考试试题视作题,2014新疆计算机一级考试试题汇总
  9. python常用运维模块_python常用模块之一
  10. php清空html_php怎么清除html代码