核心部分

  1. 外观模式: RequestFacade应用门面模式(facade)来封装HttpServletRequest。
  2. 观察者模式: 事件监听机制,控制组件生命周期的 Lifecycle 、Servlet 实例的创建、Session 的管理、Container 管理等应用了观察者模式。相关的类有LifecycleListener, ContainerListener, SessionListener。。。
  3. 责任链模式:tomcat的容器设置就是责任链模式,从Engine到Host再到Context一直到Wrapper都是通过一个链传递请求。
  4. 模板方法模式:Tomcat中就将每个生命周期阶段公共的部分固化,然后通过initInternal,startInternal,stopInternal,destoryInternal这几个钩子方法开放给子类去实现具体的逻辑。
  5. 命令模式:Tomcat 中命令模式在 Connector 和 Container 组件之间有体现,Connector 作为抽象请求者,HttpConnector 作为具体请求者。HttpProcessor 作为命令。Container 作为命令的抽象接受者,ContainerBase 作为具体的接受者。
  6. 工厂模式:在Tomcat启动的过程中,调用Connector组件的startInternal()方法:

1.外观模式

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

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

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

2.观察者模式

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

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

  

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

3.责任链模式

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

责任链模式在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核心处理流程就是通过责任链一步步的组装起来的。

4.模板方法模式

定义:模板方法模式抽象出某个业务操作公共的流程,将流程分为几个步骤,其中有一些步骤是固定不变的,有一些步骤是变化的,固定不变的步骤通过一个基类来实现,而变化的部分通过钩子方法让子类去实现,这样就实现了对系统中流程的统一化规范化管理。\

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

  

5.命令模式

定义:命令模式将请求封装为一个命令,将命令发送者和命令接受者解耦,并且所有命令对客户端来说都有统一的调用接口,使用命令模式还可以支持命令的撤销操作,在很多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处理器,其它的类似。

抄录网址

  1. Tomcat 设计模式总结(Tomcat源代码阅读系列之八)
  2. Tomcat设计模式
  3. java 23种设计模式及其在spring,tomcat,jdk中的应用
  4. Tomcat中设计模式-模板模式
  5. Tomcat中涉及哪些设计模式
  6. Tomcat用到的设计模式
  7. Tomcat 系统架构与设计模式,第 2 部分

Tomcat系列(10)——Tomcat主要设计模式5种(外观,责任链,观察者,模板方法,命令模式)的更多相关文章

  1. Java设计模式(14)责任链模式(Chain of Responsibility模式)

    Chain of Responsibility定义:Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合, ...

  2. java设计模式解析(11) Chain责任链模式

    设计模式系列文章 java设计模式解析(1) Observer观察者模式 java设计模式解析(2) Proxy代理模式 java设计模式解析(3) Factory工厂模式 java设计模式解析(4) ...

  3. php设计模式课程---5、责任链模式是什么

    php设计模式课程---5.责任链模式是什么 一.总结 一句话总结: 自己权限不够,就交给上级处理 1.选择结构怎么做到面向对象开闭原则? 也就是说if,都可以用接口的实现来实现,这样就避免了更新的时 ...

  4. Tomcat系列(11)——Tomcat 部署web应用的4种方法

    核心内容 1.在Tomcat中有四种部署Web应用的方式,分别是: (1)利用Tomcat自动部署(项目直接拷贝OR WAR包拷贝 到webapps下) (2)利用控制台进行部署(tomcat的man ...

  5. Tomcat系列(4)——Tomcat 组件及架构详细部分

    核心部分   1. 定义 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta ...

  6. Tomcat系列(9)——Tomcat 6方面调优(内存,线程,IO,压缩,缓存,集群)

    核心部分 内存 线程 IO 压缩 缓存 集群 一.JVM内存优化 Tomcat内存优化,包括内存大小,垃圾回收策略. Windows 下的catalina.bat,Linux 下的catalina.s ...

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

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

  8. Tomcat系列(3)——Tomcat 组件及架构核心部分 4类主要组件(顶层,连接器,容器,嵌套)

    1.架构图 2. 定义 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta ...

  9. Tomcat系列(7)——Tomcat类加载机制

    1. 核心部分 1. 类加载器: 通过一个类的全限定名来获取描述此类的二进制字节流. 对于任意一个类,都需要由加载他的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一 ...

随机推荐

  1. 太嚣张了!他竟用Python绕过了“验证码”

    在web页面中,经常会遇到验证码,这对于我这么一个热爱web自动化测试人员,就变成了一件头疼的事.于是千方百计找各种资源得到破解简单的验证码方法. 识别验证码 大致分如下几个步骤: 1.获取验证码图片 ...

  2. MySQL8.0 on Windows下重置root密码的BUG

    很多人都知道MySQL忘记root密码之后可以通过skip-grant-tables来暂时免密登录MySQL,从而修改root密码,但是这种方式一方面有安全隐患,另一方面也并不怎么适用于Windows ...

  3. python3通过os模块统计指定目录下文件个数

    代码: import os path = r"C:\Users\Administrator\Desktop\***" print('filenum:',len([lists for ...

  4. memcached 学习

    memcached 是什么 特点 协议简单 基于 libevent 的事件处理 内置内存存储方式 memcached 不互相通信的分布式 启动 安装 依赖 libevent 安装命令 下载地址在这个网 ...

  5. 浅析CompareAndSet(CAS)

    最近无意接触了AtomicInteger类compareAndSet(从JDK5开始),搜了搜相关资料,整理了一下 首先要说一下,AtomicInteger类compareAndSet通过原子操作实现 ...

  6. 用golang写了个统计各单位报送的信息数量的微服务

    代码很乱,bug很多,将就着看吧.参考了很多网上代码,只能说声感谢了. //cjl.ZongHeInfo.1.0 //目的:对各部门报上来的信息数量进行排名 //思路:预计一年信息量不超过100M,全 ...

  7. 使用RAP2和Mock.JS实现Web API接口的数据模拟和测试

    最近一直在思考如何对Web API的其接口数据进行独立开发的问题,随着Web API的越来越广泛应用,很多开发也要求前端后端分离,例如统一的Web API接口后,Winform团队.Web前端团队.微 ...

  8. Educational Codeforces Round 61 (Rated for Div. 2)-C. Painting the Fence 前缀和优化

    题意就是给出多个区间,要求去掉两个区间,使得剩下的区间覆盖范围最大. 当然比赛的时候还是没能做出来,不得不佩服大佬的各种姿势. 当时我想的是用线段树维护区间和,然后用单点判0,维护区间间断个数.然后打 ...

  9. java集合-HashMap源码解析

    HashMap 键值对集合 实现原理: HashMap 是基于数组 + 链表实现的. 通过hash值计算 数组索引,将键值对存到该数组中. 如果多个元素hash值相同,通过链表关联,再头部插入新添加的 ...

  10. Django Models 查询操作

    1.准备数据表: from django.db import models class City(models.Model): name=models.CharField(max_length=32) ...