当前位置: 首页 > 科技观察

深入浅出:Tomcat应用服务器实现中的设计模式应用浅析

时间:2023-03-18 19:32:24 科技观察

简单解释:浅析设计模式在Tomcat应用服务器实现中的应用总结。它代表了最佳实践,通常被经验丰富的面向对象软件开发人员采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员在相当长的一段时间内反复试验的结果。使用设计模式的目的:为了代码的复用性,让代码更容易被别人理解,保证代码的可靠性。设计模式让代码编写真正工程化;设计模式是建筑物的基石背景,就像建筑物的结构一样。目前在业界最著名的是“四人帮()”的23个经典设计模式。有足够精力学习或者想更进一步的网友建议研究一下,受益匪浅。话又说回来,设计模式出现的根本原因是为了重用代码,增加可维护性。那么如何实现代码复用呢?面向对象有几个原则(这里不讨论具体原则的含义和应用):(单一职责原则SRP)(开闭原则,OCP),(里氏替换原则,LSP),(依赖倒置原则,DIP)),(接口隔离原则,ISP),复合/聚合重用原则(Composite/AggregateReusePrinciple,CARP),最少知识原则(PrincipleofLeastKnowledge,PLK,也叫)。开闭原则是唯心主义的,是面向对象设计的最终目标。其他几个可以看作是开闭原理的实现方法。那么,在设计模式的好处和设计原则的指导下,我们简单了解一下相关模式在Web应用服务器行业最流行的Tomcat中的应用,以供参考和学习。另外,这里特别提醒一点,设计模式的应用一定要结合其具体的应用场景和实际需求,来确定和评估其对应的设计模式、需要解决的问题、具体的实施方案、好的效果,而模式不能用于模式。.让我们来看看Tomcat应用服务器中的设计模式。(在此感谢许凌波的解读和分享)二、Tomcat实现中的设计模式2.1Facade设计模式Facade设计模式在Tomcat中有很多地方用到,包括Request和Response对象的封装,StandardWrapper到ServletConfig的封装,ApplicationContext这个设计模式用在ServletContext包中。1.门面设计模式的原理这种设计模式用在很多场合,那么这种设计模式能做什么呢?顾名思义,门面设计模式就是将一些东西封装到一个门面中,以便于与他人交流,就像一个国家的外交部。这种设计模式主要用于大型系统中有多个子系统的情况。这些子系统之间必然涉及到相互通信,但是每个子系统不能过多地将自己的内部数据暴露给其他系统,否则就没有必要划分子系统。每个子系统都会设计一个门面来封装其他系统感兴趣的数据,并通过这个门面访问。这就是门面设计模式的意义。门面设计模式示意图如下:图1.门面设计模式允许Client只能访问Fa?ade提供的数据,这是门面设计模式的关键。至于Client如何访问Fa?ade和Subsystem,如何提供没有规定呀。2.Tomcat的门面设计模式示例Tomcat中的门面设计模式被大量使用,因为Tomcat中有许多不同的组件,每个组件都需要相互交互。使用外观模式隔离数据是一种很好的方式。下面是Request上使用的门面设计模式:图2Request门面设计模式类图从图中可以看出,HttpRequestFacade类封装了HttpRequest接口提供数据,通过HttpRequestFacade访问的数据被代理到HttpRequest,通常封装的对象都设置为private或者protected的访问修饰,防止在Fa?ade中直接访问。2.2观察者设计模式这种设计模式也是一种常用的设计方法,通常称为发布-订阅模式,即事件监听机制,通常在事件发生前后触发一些操作。1、观察者模式的原理观察者模式的原理也很简单,就是当你在做某事的时候,总有人在盯着你看,当你在做它感兴趣的事情时,它会跟着做其他事情。但是盯着你的人必须在你那里注册,否则你无法通知它。观察者模式通常包括以下角色:·Subject:是一个抽象的Subject,负责管理所有观察者的引用,定义主要的事件操作。·ConcreteSubject:具体主体,实现抽象主体定义的所有接口,并在发生变化时通知所有观察者。·Observer:观察者:监听主题变化时对应的操作界面。2、Tomcat的观察者模式的一个例子Tomcat中的观察者模式也有很多地方用到。上面说的控制组件生命周期的Lifecycle就是这种模式的体现,与Servlet实例的创建、Session管理、Container等原理相同。下面主要看一下Lifecycle的具体实现。LifecycleObserverPattern结构图:图3.LifecycleObserverPattern结构图在上面的结构图中,LifecycleListener代表一个抽象的观察者,它定义了一个lifecycleEvent方法,也就是当主题发生变化时要执行的方法。ServerLifecycleListener代表一个具体的观察者,它实现了LifecycleListener接口的方法,也就是这个具体观察者的具体实现。Lifecycle接口表示一个抽象主题,它定义了用于管理观察者的方法和其他用于它所做的事情的方法。StandardServer代表一个具体的主题,它实现了抽象主题的所有方法。这里Tomcat对观察者进行了扩展,增加了另外两个类:LifecycleSupport和LifecycleEvent,作为辅助类扩展了观察者的功能。LifecycleEvent使得定义事件类别成为可能,不同的事件可以有不同的处理,更加灵活。LifecycleSupport类作为主题对多个观察者的管理的代理,这个管理被抽取出来统一实现。以后修改的话,只需要修改LifecycleSupport类即可,不需要修改所有具体主题,因为所有具体主题对观察者的操作都是一样的。它被委托给LifecycleSupport类。这可以认为是观察者模式的改进版本。LifecycleSupport调用观察者的方法代码如下:清单1.LifecycleSupport中的fireLifecycleEvent方法主体如何通知观察者?看下面的代码:清单2.容器中的start方法2.3Command设计模式前面把Tomcat的两个核心组件Connector和Container比作一对夫妻。男人将接受的请求以命令的形式递给了女主人。Connector和Container对应,Connector通过命令方式调用Container。1、命令模式的原理命令模式的主要作用是对命令进行封装,将发出命令的职责和执行命令的职责分开。也是功能的划分。不同的模块可以不同地解释相同的命令。以下是命令模式通常包括以下角色:1)Client:创建命令并确定接收者2)Command命令:命令接口定义抽象方法3)ConcreteCommand:具体命令负责调用相应的操作4)Invoker请求者:负责调用命令对象执行请求5)Receiver接收者:负责一个请求的具体实现和执行2、Tomcat中命令模式的一个例子Tomcat中的命令模式体现在Connector和Container组件,Tomcat作为一个应用服务器无疑会收到很多请求,如何分配和执行这些请求是一个必须的功能。我们来看看Tomcat是如何实现命令模式的。下面是Tomcat命令模式的结构图:图4.Tomcat命令模式的结构图。Connector是抽象的请求者,HttpConnector是具体的请求者。HttpProcessor作为命令。Container作为命令的抽象接收者,ContainerBase作为具体的接收者。客户端是应用服务器的服务器组件。服务器首先创建命令请求者HttpConnector对象,然后创建命令HttpProcessor命令对象。然后将命令对象传递给命令接收者ContainerBase容器来处理命令。命令最终由Tomcat的Container执行。命令可以作为队列进来,容器也可以以不同的方式处理请求。比如HTTP1.0协议和HTTP1.1的处理方式会有所不同。2.4责任链模式Tomcat中最容易找到的设计模式之一是责任链模式。这种设计模式也是Tomcat中Container设计的基础。整个容器通过一条链连接在一起,这条链总是正确地将请求传递给最终处理请求的servlet。1.责任链模式原则。责任链模式是很多对象都有对其下属的引用,并连接起来形成一个链。请求在此链上传递,直到链上的对象处理该请求。或者每个对象都可以处理请求并传递给下一个公司,直到最后处理完链上的每个对象。这样,可以在不影响客户端的情况下,将任意处理节点添加到链中。通常责任链模式包括以下角色:1)Handler(抽象处理器):定义处理请求的接口2)ConcreteHandler(具体处理器):处理请求,或传递给下一个家族的具体类2,职责在Tomcat中链式模式的例子这种设计模式在tomcat中几乎完全被使用。tomcat的容器设置是责任链模式。从Engine到Host到Context再到Wrapper,请求通过一个链条传递。Tomcat中责任链模式的类结构图如下:图5.Tomcat中责任链模式的结构图。上图基本描述了使用责任链模式的四个子容器的类结构图,以及责任链模式对应的作用。Container扮演一个抽象的processor,具体的processor由StandardEngine等子容器扮演。不同于标准的责任链,这里引入了Pipeline和Valve接口。他们在做什么?实际上,Pipeline和Valve扩展了这条链条的功能,使得链条向下传递的过程中可以接受外部干预。管道是连接各个子容器的管道。里面传递的Request和Response对象就像水管里流动的水,Valve就是管子上的小开口,让你可以接触到里面的水,做一些额外的事情。为了防止水被抽出而没有流入下一个容器,每段管道必须始终有一个节点以确保它可以流到下一个子容器,因此每个容器都有一个StandardXXXValve。只要涉及到这种链式处理流程,这是一个值得借鉴的模式。