Tomcat中设计模式

1 Tomcat中设计模式

Tomcat中用了很多设计模式,如模板模式、工厂模式和单例模式等一些常用的设计模式,对这些模式大家都比较熟悉,下面介绍一些在Tomcat中用到的其他设计模式

1.1 门面设计模式

门面设计模式在Tomcat中有多处使用,在RequestResponse对象封装、从StandardWrapperServletConfig 封装、从 ApplicationContextServletContext 封装中都用到了这种设计模式。

1.1.1 门面设计模式的原理

这么多场合都用到了这种设计模式,那这种设计模式究竟能有什么作用呢?顾名思义,就是将一个东西封装成一个门面,好与大家更容易地进行交流,就像一个国家的外交部一样。
点击了解JAVA设计模式之外观模式
这种设计模式主要用在在一个大的系统中有多个子系统时,这时多个子系统肯定要相互通信,但是每个子系统又不能将自己的内部数据过多地暴露给其他系统,不然就没有必要划分子系统了。每个子系统都会设计一个门面,把别的系统感兴趣的数据封装起来,通过这个门面来进行访问。这就是门面设计模式存在的意义。

门面设计模式的示意图如图11-14所示。
在这里插入图片描述
Client只能访问Facade中提供的数据是门面设计模式的关键,至于Client如何访问FapadeSubsystem、如何提供Facade门面设计模式并没有规定得很严格。

1.1.2 Tomcat的门面设计模式示例

Tomcat中门面设计模式使用得很多,因为在Tomcat中有很多组件,每个组件要相互交互数据,用门面设计模式隔离数据是个很好的方法。
Request上使用的门面设计模式类图如图11-15所示。
在这里插入图片描述
从图11-15中可以看出,HttpRequestFacade类封装了 HttpRequest接口,能够提供数据,通过HttpRequestFacade访问到的数据都被代理到HttpRequest中,通常被封装的对象都被设为Private或者Protected,以防止在Facade中被直接访问。

1.2 观察者设计模式

这种设计模式也是常用的设计方法,通常也叫发布-订阅模式,也就足事件监听机制。通常在某个事件发生的前后会触发一些操作。

1.2.1 观察者模式的原理

观察者模式的原理也很简单,就是你在做事时旁边总有一个人盯着你,当你做的功情是他感兴趣的亊情时,他就会跟着做另外一些事情。但是盯着你的人必须要到你那里登记,不然你无法通知他。观察者模式通常包含下面几个角色:

  • Subject抽象主题:它负责管理所有观察者的引用,同时定义主要的事件操作。
  • ConcretcSubject具体主题:它实现了抽象主题定义的所有接口,当自己发生变化时,会通知所有观察者。
  • Observer观察者:监听主题发生变化的操作接口。

点击了解JAVA设计模式之观察者模式

1.2.2 Tomcat的观察者模式示例

Tomcat中观察者模式也有多处使用,前面讲的控制组件生命周期的Lifecyde就是这种模式的体现,还有对Servlet实例的创建、Session的管理、Container等都是同样的原理。下面主要看一卜Lifecycle的具体实现。
Lifecycle的观察者模式结构如图11-16所示
在这里插入图片描述

在上面的结构图中,LifecycleListener代表的是抽象观察者,它定义了一个lifecycleEvent方法,这个方法就是当主题变化时要执行的方法。ServerLifecycleListener代表的是具体的观察者,它实现了 LifecycleListener接口的方法,就是这个具体的观察者具体的实现方式

Lifecycle接口代表的是抽象主题,它定义了管理观察者的方法和它要做的其他方法。而StandardServer代表的是具体主题,它实现了抽象 主题的所有方法。这里Tomcat对观察者做了扩展,增加了另外两个类:LifecycleSupport和LifecycleEvent,它们作为辅助 类扩展了观察者的功能。LifecycleEvent可以定义事件类別,对不同的半件可区别处理,更加灵活LifecycleSupport类代理了主 题对多观察者的管理,将这个管理抽出来统一实现,以后如果修改只要修改LifecycleSupport类就可以了,不需要去修改所有的具体主题,因为所有具体主题对观察者的操作都被代理给LifecycleSupport类了。这可以认为是观察者模式的改进版

LifecycleSupport调用观察者的方法代码如下:

public void fireLifecycleEvent(String type. Object data)   
{  
    LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);  
    LifecycleListener interestedf[] = null;  
    synchronized (listeners)   
    {  
        interested = (LifecycleListener[]) listeners.clone ();  
    }  
    for (int i = 0; i < interested.length; i++)  
        interested[i].lifecycleEvent(event);  
}  
public void start() throws LifecycleException   
{  
    lifecycle.fireLifecycleEvent(BEFORE_START_EVENTT, null);  
    lifecycle.fireLifecycleEvent(START_EVENT, null);  
    started = true;  
    synchronized (services)   
    {  
        for (int i = 0; i < services.length; i++)      
        {  
            if (services[i] instanceof Lifecycle)  
                ((Lifecycle) services[i]).start();    
        }  
    }  
    lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);  
}  

1.3 命令设计模式

Connector是通过命令模式调用Container

1.3.1 命令模式的原理

命令模式的主要作用就是封装命令,把发出命令的责任和执行命令的责任分开,也是一种功能的分工。不同的模块可以对同一个命令做出不同的解释。

命令模式通常包含下面几个角色:

  • Client:创建一个命令,并决定接受者。
  • Command:命令接口,定义一个抽象方法。
  • ConcreteCommand:具体命令,负责调用接受者的相应操作。
  • Invoker:请求者,负责调用命令对象执行请求。
  • Receiver:接受者,负责具体实施和执行一次请求。

点击了解JAVA设计模式之命令模式

1.3.2 Tomcat中命令模式的示例

Tomcat中命令模式在ConnectorContainer组件之间有体现,Tomcat作为一个应用服务器,无疑会接收到很多请求,如何分配和执行这些请求是必须的功能。

下面看一下Tomcat是如何实现命令模式的,图1M7是Tomcat命令模式的结构图
在这里插入图片描述

Connector作为抽象请求者,HttpConnector作为具体请求者,HttpProcessor作为命令.Container作为命令的抽象接受者,ContainerBase作为具体的接受者,客户端就是应用服务器Server组件了。Server首先创建命令请求者 HttpConnector对象,然后创建命令HttpProcessor对象,再把命令对象交给命令接受者ContainerBase容器来处理。命令最终是被TomcatContainer执行的。命令可以以队列的方式进来,Container也可以以不同的方式来处理请求,如HTTP1.0和 HTTP1.1的处理方式就不同。

1.4 责任链设计模式

Tomcat中一个最容易发现的设计模式就是责任链设计模式,这个设计模式也是在TomcatContainer设计的基础,整个容器就是通过一个链连接在一起的,这个链一直将请求正确地传递给最终处理请求的那个Servlet

1.4.1 责任链模式原理

责任链模式就是很多对象由每个对象对其下家的引用而连接起来形成一条链,请求在这条链上传递,直到链上的某个对象处理此请求,或者每个对象都可以处理请求,并传给下家,直到最终链上每个对象都处理完。这样可以不影响客户端而能够在链上增加任意的处理节点。

通常责任链模式包含下面几个角色:

  • Handler (抽象处理者):定义一个处理请求的接口。
  • ConcreteHandler (具体处理者):处理请求的具体类,或者传给“下家”。

1.4.2 Tomcat中的责任链模式示例

Tomcat中这种设计模式几乎被完整地使用了,Tomcat的容器设置就是责任链模式,从EngineHost再到Context —直到Wrapper都通过一个链传递请求。
Tomcat中的责任链模式的类结构图如图11-18所示。
在这里插入图片描述

上图基本上描述了 4个子容器使用责任链模式的类结构图,在对应的责任链模式的角色Container扮演抽象处理者角色,具体处理者由StandardEngine等子容器扮演。与标准的责任链不同的是,这里引入了PipelineValve接口,它们有什么作用呢?
实际上PipelineValve扩展了这个链的功能,使得在链向下传递的过秤中,能够接收外界的干预。Pipeline就是连接每个子容器的管子,里面传递的RequestResponse对象好比管子里流的水,而Valve就是在这个管子上开的一个个小孔子,让你有机会接触到里面的水,做一些额外 的事情。
为了防止水被引出来而不流到下一个容器中,在每一段管子最后总有一个节点保证它一定能流到下一个子容器,所以每个容器都有一个StandardXXXValve。只要涉及这样一种链式的处理流程,这便是一个非常值得借鉴的模式

posted @ 2022-03-11 16:45  上善若泪  阅读(161)  评论(0编辑  收藏  举报