07 | Tomcat如何实现一键式启停?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
Tomcat实现一键式启停的关键在于Lifecycle接口的应用,该接口定义了组件的生命周期方法,实现了组合模式和观察者模式。通过LifecycleBase抽象基类的设计,实现了公共逻辑的重用,同时考虑了系统的可扩展性和重用性。Tomcat运用了组合模式、观察者模式、骨架抽象类和模板方法,发挥了面向对象思想和设计模式的优势。容器组件都扩展了ContainerBase,这也是一个骨架抽象类,它们共同的逻辑需要由ContainerBase来实现。通过对Tomcat组件的生命周期管理的深入理解,读者可以快速了解Tomcat如何实现一键式启停以及相关的技术特点。
《深入拆解 Tomcat & Jetty 》,新⼈⾸单¥68
全部留言(52)
- 最新
- 精选
- 一路远行ContainerBase提供了针对Container接口的通用实现,所以最重要的职责包含两个: 1) 维护容器通用的状态数据 2) 提供管理状态数据的通用方法 容器的关键状态信息和方法有: 1) 父容器, 子容器列表 getParent, setParent, getParentClassLoader, setParentClassLoader; getStartChildren, setStartChildren, addChild, findChild, findChildren, removeChild. 2) 容器事件和属性监听者列表 findContainerListeners, addContainerListener, removeContainerListener, fireContainerEvent; addPropertyChangeListener, removePropertyChangeListener. 3) 当前容器对应的pipeline getPipeline, addValve. 除了以上三类状态数据和对应的接口,ContainerBase还提供了两类通用功能: 1) 容器的生命周期实现,从LifecycleBase继承而来,完成状态数据的初始化和销毁 startInternal, stopInternal, destroyInternal 2) 后台任务线程管理,比如容器周期性reload任务 threadStart, threadStop,backgroundProcess. 想了解更多技术细节,可以参考源码org.apache.catalina.core.ContainerBase,有源码有真相。
作者回复: 👍
2019-05-262101 - allean原理理解之后特别想看看源码是怎么写的,不看源码总感觉不踏实🤣,老师在介绍组件原理之后可不可以指明怎么启动Tomcat源码,并debug啊,多谢
作者回复: 建议跟SpringBoot那样,用嵌入式方式启动Tomcat,这里有例子: https://github.com/heroku/devcenter-embedded-tomcat
2019-05-25549 - why- 系统启动时会创建,组装,启动组件,服务停止时释放资源销毁组件。 - 组件间由两层关系 - 组件有大有小, 大组件管理小组件( Server 管 Service ) - 组件有内有外, 外层控制内层( 连接器控制容器 ) - 关系决定创建应有的顺序 - 先创建子组件, 再创建父组件, 子组件注入父组件 - 先创建内层组件, 再创建外层, 内层注入外层组件 - 以上方法存在的问题: 代码混乱/组件遗漏/不利扩展 - 解决方法: 通用, 统一的组件管理 - LifeCycle 接口 ( 通用性 → 组合模式 ) - 不变: 组件创建, 初始化, 启动等状态 - 变化: 具体启动方法 - 将不变抽象为接口 LifeCycle, 包括四个方法 init start stop destroy; 以下为组合模式: - 父组件 init 方法创建子组件并调用其 init 方法 - 父组件 start 调用 子组件 start 方法 - 只要调用最顶层 init start 就可以启动应用 - LifeCycle 事件 ( 扩展性 → 观察者模式 ) - 系统可扩展性, 应遵循开闭原则: 不能修改已有的类, 可以定义新的类 - 上层 init 等方法触发下层 init 等方法, 把状态当做事件, 事件有对应Listener; Listener可方便添加和删除, 此为观察者模式 - 在 LifeCycle 中加入两个方法: 添加/删除Listener, 并用 Enum 定义状态及其对应触发事件 - LifeCycleBase 抽象基类 ( 重用性 → 模板设计模式 ) - 接口实现类有一些相同的逻辑, 定义一个基类实现共同的逻辑 - 基类会定义一些抽象方法, 调用这些方法实现子类逻辑 - LifeCycleBase 实现 LifeCycle 接口, 实现通用逻辑: 状态转变/维护, 事件触发, 监控器添加/删除, 调用子类逻辑 - LifeCycleBase 抽象基类抽象方法改名, initInternal 等, 避免与 init 重名; initInternal 会调用子组件的 init 方法 - Listener注册, 分为两种情况 - Tomcat 自定义的Listener, 父组件创建子组件是注册到子组件中 - 可在 server.xml 中定义自己的Listener, 由 Tomcat 解析, 创建Listener并注册到组件中 - 容器类生命周期管理接口与功能接口分开 → 接口分离原则
作者回复: 👍
2019-05-3020 - 尔冬橙老师,会不会考虑出一门课:深入拆解spring?我特别想听老师讲Spring架构的的设计,和里面用到的设计模式
作者回复: 掌握了分析源码的方法,再分析Spring都不是难事。
2019-06-02216 - WL请问一下老师Tomcat为什么要在LifeCycleBase中定义一系列的***internal()让子类取调用, 为什么不是子类实现接口的init()方法呢, 这一点我不是很理解, 希望老师指点一下.
作者回复: init方法里有一些”通用的逻辑“对各个子类都适用,如果让每个子类都重复实现一编,代码不久重复了吗,于是这些”逻辑“让LifeCycleBase来做,其实就是实现了模板,子类再在这个模板上填充自己的内容。
2019-05-26215 - nsn_huang这是Tomcat8.5版本的源码,基于Maven和IDEA,希望大家一起学习,一起进步。https://blog.csdn.net/sougou_1323/article/details/90597079
作者回复: 谢谢分享!
2019-05-2711 - Monday思考题 1,容器的创建/初始化/销毁 2,容器添加/删除子容器 3,如果还要监听容器状态变化的话还需要有添加/移除事件的方法。 请指正。 本节收获,干货干货。 多种设计模式还带Tomcat设计的应用场景,面试设计模式绝对加分项(我还没消化) 问题:进入架构篇,就处于下面这种学习状态。 1,觉得老师讲得很有道理 2,被动的吸收着知识点,没有自己的思路 3,一看文档就感觉自己似乎是懂了,因为提不出好问题,一合上文档就感觉本节我没来过 老师有没有好的建议,谢谢!
作者回复: 你思考题回答的不错啊,还可以想想实际工作中是不是也有类似的场景,可以模仿这种设计。
2019-05-25210 - 飞翔老师 我从 tomcat class 里边的main方法找,跟踪到 catalina里边的load方法,在这个方法里边有digester.parse(inputSource); 我觉得这个应该是具体读serverxml的,但是在往下跟踪始终找不到哪里读server.xml 实例化server等,求指导
作者回复: 可以在Server的构造函数里下断点,你会发现是XML解析器通过反射创建的
2019-07-158 - -W.LI-老师好!之前设计模式看过好几遍,总感觉用不上,虽然知道是自己对设计思想的理解不够深入导致的。又苦于找不到方法,看了老师的分析对设计模式,和设计原则又有了进一步的了解。问题1:对于变于不变的界定标准,哪些方法需要抽象为接口。老师有啥好的建议么。问题2:spring的event,发布一个事件时会把事件放入map.然后轮训所有的所有的观察者。观察者和event很多的时候,内存等开销,会成为性能瓶颈么?比如处理事件的逻辑比较复杂或者需要IO操作。会有处理速度跟不上事件发生的速度这样的情况导致OOM的么?
作者回复: 1.这个要根据具体场景来的,简单来说如果你需要用if-else来实现某个逻辑,这是可能是变化点。 2.这种情况下,对event的处理考虑用线程池。
2019-05-258 - Geek_ebda96老师,你的意思是配置在server.xml里的connector的线程池是tomcat对于一个应用的全局线程池,用于接受请求的socketprocessor会放到这个线程池里,假如这个应用里面有后台一些定时job或或其他需要异步线程处理的业务,也会从这个大的线程池里取线程处理,不会再单独做新建线程?
作者回复: Connector上的线程池负责处理这个它所接收到的所有请求。一个Connector有一个线程池。 其他的后台任务也有专门的线程池,不会占用Connector的线程池。
2019-06-067