当前位置: 首页 > news >正文

备案博客域名做视频网站会怎么样/国内最好的危机公关公司

备案博客域名做视频网站会怎么样,国内最好的危机公关公司,网站必须做诚信认证吗,商城建站报价方案Tomcat如何实现一键式启停 Hi,我是阿昌,今天学习的是关于Tomcat是如何实现一键式启停的。 先复习一下前几天学习的Tomcat架构内容: 上面这张图描述了组件之间的静态关系,如果想让一个系统能够对外提供服务,我们需要创…

Tomcat如何实现一键式启停

Hi,我是阿昌,今天学习的是关于Tomcat是如何实现一键式启停的。

先复习一下前几天学习的Tomcat架构内容:

在这里插入图片描述
上面这张图描述了组件之间的静态关系,如果想让一个系统能够对外提供服务,我们需要创建、组装并启动这些组件;

在服务停止的时候,我们还需要释放资源,销毁这些组件,因此这是一个动态的过程。

也就是说,Tomcat 需要动态地管理这些组件的生命周期。在我们实际的工作中,如果你需要设计一个比较大的系统或者框架时,你同样也需要考虑这几个问题:

如何统一管理组件的创建、初始化、启动、停止和销毁?如何做到代码逻辑清晰?如何方便地添加或者删除组件?如何做到组件启动和停止不遗漏、不重复?

仔细分析过这些组件,可以发现它们具有两层关系

  • 第一层关系是组件有大有小,大组件管理小组件,比如 Server 管理 Service,Service 又管理连接器和容器。
  • 第二层关系是组件有外有内,外层组件控制内层组件,比如连接器是外层组件,负责对外交流,外层组件调用内层组件完成业务功能。也就是说,请求的处理过程是由外层组件来驱动的。

这两层关系决定了系统在创建组件时应该遵循一定的顺序

  • 第一个原则是先创建子组件,再创建父组件,子组件需要被“注入”到父组件中。
  • 第二个原则是先创建内层组件,再创建外层组件,内层组件需要被“注入”到外层组件。

因此,最直观的做法就是将图上所有的组件按照先小后大、先内后外的顺序创建出来,然后组装在一起。

这个思路其实很有问题!因为这样不仅会造成代码逻辑混乱和组件遗漏,而且也不利于后期的功能扩展。

为了解决这个问题,我们希望找到一种通用的、统一的方法来管理组件的生命周期,就像汽车“一键启动”那样的效果。


一、一键式启停:Lifecycle 接口

设计就是要找到系统的变化点不变点

这里的不变点就是每个组件都要经历创建、初始化、启动这几个过程,这些状态以及状态的转化是不变的。

而变化点是每个具体组件的初始化方法,也就是启动方法是不一样的。因此,我们把不变点抽象出来成为一个接口,这个接口跟生命周期有关,叫作 Lifecycle。

Lifecycle 接口里应该定义这么几个方法:

  • init
  • start
  • stop
  • destroy

每个具体的组件去实现这些方法。理所当然,在父组件的 init 方法里需要创建子组件并调用子组件的 init 方法。

同样,在父组件的 start 方法里也需要调用子组件的 start 方法,因此调用者可以无差别的调用各组件的 init 方法和 start 方法,这就是组合模式的使用,并且只要调用最顶层组件,也就是 Server 组件的 init 和 start 方法,整个 Tomcat 就被启动起来了。

下面是 Lifecycle 接口的定义。
在这里插入图片描述


二、可扩展性:Lifecycle 事件

针对系统的可扩展性。因为各个组件 init 和 start 方法的具体实现是复杂多变的,比如在 Host 容器的启动方法里需要扫描 webapps 目录下的 Web 应用,创建相应的 Context 容器,如果将来需要增加新的逻辑,直接修改 start 方法?

这样会违反开闭原则,那如何解决这个问题呢?

开闭原则说的是为了扩展系统的功能,你不能直接修改系统中已有的类,但是你可以定义新的类。

组件的 init 和 start 调用是由它的父组件的状态变化触发的,上层组件的初始化会触发子组件的初始化,上层组件的启动会触发子组件的启动,因此我们把组件的生命周期定义成一个个状态,把状态的转变看作是一个事件。

而事件是有监听器的,在监听器里可以实现一些逻辑,并且监听器也可以方便的添加和删除,这就是典型的观察者模式

具体来说就是在 Lifecycle 接口里加入两个方法:

  • 添加监听器
  • 删除监听器。

除此之外,我们还需要定义一个 Enum 来表示组件有哪些状态,以及处在什么状态会触发什么样的事件。

因此 Lifecycle 接口和 LifecycleState 就定义成了下面这样。

在这里插入图片描述
从图上你可以看到,组件的生命周期有 NEW、INITIALIZING、INITIALIZED、STARTING_PREP、STARTING、STARTED 等,而一旦组件到达相应的状态就触发相应的事件,比如 NEW 状态表示组件刚刚被实例化;

而当 init 方法被调用时,状态就变成 INITIALIZING 状态,这个时候,就会触发 BEFORE_INIT_EVENT 事件,如果有监听器在监听这个事件,它的方法就会被调用。


三、重用性:LifecycleBase 抽象基类

有了接口,我们就要用类去实现接口。

一般来说实现类不止一个,不同的类在实现接口时往往会有一些相同的逻辑,如果让各个子类都去实现一遍,就会有重复代码

那子类如何重用这部分逻辑呢?其实就是定义一个基类来实现共同的逻辑,然后让各个子类去继承它,就达到了 重用的目的

而基类中往往会定义一些抽象方法,所谓的抽象方法就是说基类不会去实现这些方法,而是调用这些方法来实现骨架逻辑。抽象方法是留给各个子类去实现的,并且子类必须实现,否则无法实例化。比如宝马和荣威的底盘和骨架其实是一样的,只是发动机和内饰等配套是不一样的。

底盘和骨架就是基类,宝马和荣威就是子类。仅仅有底盘和骨架还不是一辆真正意义上的车,只能算是半成品,因此在底盘和骨架上会留出一些安装接口,比如安装发动机的接口、安装座椅的接口,这些就是抽象方法。宝马或者荣威上安装的发动机和座椅是不一样的,也就是具体子类对抽象方法有不同的实现。

回到 Lifecycle 接口,Tomcat 定义一个基类 LifecycleBase 来实现 Lifecycle 接口,把一些公共的逻辑放到基类中去,比如生命状态的转变与维护、生命事件的触发以及监听器的添加和删除等,而子类就负责实现自己的初始化、启动和停止等方法。

为了避免跟基类中的方法同名,我们把具体子类的实现方法改个名字,在后面加上 Internal,叫 initInternal、startInternal 等。

基类 LifecycleBase 后的类图

在这里插入图片描述

从图上可以看到,LifecycleBase 实现了 Lifecycle 接口中所有的方法,还定义了相应的抽象方法交给具体子类去实现,这是典型的模板设计模式

下面是 LifecycleBase 的 init 方法实现。

@Override
public final synchronized void init() throws LifecycleException {//1. 状态检查if (!state.equals(LifecycleState.NEW)) {invalidTransition(Lifecycle.BEFORE_INIT_EVENT);}try {//2.触发INITIALIZING事件的监听器setStateInternal(LifecycleState.INITIALIZING, null, false);//3.调用具体子类的初始化方法initInternal();//4. 触发INITIALIZED事件的监听器setStateInternal(LifecycleState.INITIALIZED, null, false);} catch (Throwable t) {...}
}

这个方法逻辑比较清楚,主要完成了四步:
第一步,检查状态的合法性,比如当前状态必须是 NEW 然后才能进行初始化。

第二步,触发 INITIALIZING 事件的监听器:

setStateInternal(LifecycleState.INITIALIZING, null, false);

在这个 setStateInternal 方法里,会调用监听器的业务方法。

第三步,调用具体子类实现的抽象方法 initInternal 方法。我在前面提到过,为了实现一键式启动,具体组件在实现 initInternal 方法时,又会调用它的子组件的 init 方法。

第四步,子组件初始化后,触发 INITIALIZED 事件的监听器,相应监听器的业务方法就会被调用。

setStateInternal(LifecycleState.INITIALIZED, null, false);

总之,LifecycleBase 调用了抽象方法来实现骨架逻辑。

那LifecycleBase 负责触发事件,并调用监听器的方法,那是什么时候、谁把监听器注册进来的呢?

分为两种情况:

  • Tomcat 自定义了一些监听器,这些监听器是父组件在创建子组件的过程中注册到子组件的。
    比如 MemoryLeakTrackingListener 监听器,用来检测 Context 容器中的内存泄漏,这个监听器是 Host 容器在创建 Context 容器时注册到 Context 中的。
  • 我们还可以在server.xml中定义自己的监听器,Tomcat 在启动时会解析server.xml,创建监听器并注册到容器组件。

四、生周期管理总体类图

总体类图

在这里插入图片描述
图中的 StandardServer、StandardService 等是 Server 和 Service 组件的具体实现类,它们都继承了 LifecycleBase。StandardEngine、StandardHost、StandardContext 和 StandardWrapper 是相应容器组件的具体实现类,因为它们都是容器,所以继承了 ContainerBase 抽象基类,而 ContainerBase 实现了 Container 接口,也继承了 LifecycleBase 类,它们的生命周期管理接口和功能接口是分开的,这也符合设计中·接口分离·的原则。


五、总结

Tomcat 为了实现一键式启停以及优雅的生命周期管理,并考虑到了可扩展性和可重用性,将面向对象思想和设计模式发挥到了极致,分别运用了组合模式观察者模式骨架抽象类模板方法

如果你需要维护一堆具有父子关系的实体,可以考虑使用组合模式

观察者模式听起来“高大上”,其实就是当一个事件发生后,需要执行一连串更新操作。

传统的实现方式是在事件响应代码里直接加更新逻辑,当更新逻辑加多了之后,代码会变得臃肿,并且这种方式是紧耦合的、侵入式的。而观察者模式实现了低耦合、非侵入式的通知与更新机制。

模板方法在抽象基类中经常用到,用来实现通用逻辑。


http://www.jmfq.cn/news/4751515.html

相关文章:

  • 初中做网站软件/网站运营指标
  • 免费注册店铺位置/抖音seo培训
  • 网站后台登陆验证码不显示/郑州百度seo
  • 网站建设概念股/百度推广公司怎么代理到的
  • 广州番禺区房价/网络营销企业网站优化
  • 品牌的手机网站制作/网络营销的特点主要包括什么
  • 建设网站需要的硬件设备/爱用建站
  • 包头做网站的/手机百度2020最新版
  • 字母logo设计生成器/电商网站seo怎么做
  • 珠海pc网站建设/惠州网站建设方案推广
  • 美国人做网站/全网搜索指数
  • 重庆妇科医院推荐/百度seo发包工具
  • 网站怎么做拉新/网站秒收录工具
  • 随州公司做网站/关键词优化推广排名软件
  • 公司自己做网站/深圳百度seo怎么做
  • wordpress直接上传视频网站/sem竞价推广托管
  • 宿迁西楚房产网/深圳市企业网站seo营销工具
  • 豪禾创意海报设计理念/济南seo培训
  • 临海手机网站/电商还有发展前景吗
  • 智慧团建学生登录入口手机版/宁波受欢迎全网seo优化
  • 荥阳市城乡规划和建设局网站/好的在线crm系统
  • 建网站收费吗/最强大的搜索引擎
  • 与建设有关的政府网站/网络营销方案如何写
  • 网站设计需求/昆明seo关键词
  • 南汇集团网站建设/整站seo怎么做
  • vps做网站空间/推广app软件
  • 做兼职网站有哪些/百度云盘搜索
  • 技术支持 随州网站建设/网站收录一般多久
  • 网站毕业设计论文模板/长沙网络推广外包
  • 国内最先做弹幕的网站/凡科网怎么建网站