深入拆解Tomcat & Jetty
李号双
eBay技术主管
立即订阅
6067 人已学习
课程目录
已完结 44 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | Java程序员如何快速成长?
免费
模块一 必备基础 (4讲)
01 | Web容器学习路径
02 | HTTP协议必知必会
03 | 你应该知道的Servlet规范和Servlet容器
04 | 实战:纯手工打造和运行一个Servlet
模块二 整体架构 (9讲)
05 | Tomcat系统架构(上): 连接器是如何设计的?
06 | Tomcat系统架构(下):聊聊多层容器的设计
07 | Tomcat如何实现一键式启停?
08 | Tomcat的“高层们”都负责做什么?
09 | 比较:Jetty架构特点之Connector组件
10 | 比较:Jetty架构特点之Handler组件
11 | 总结:从Tomcat和Jetty中提炼组件化设计规范
12 | 实战:优化并提高Tomcat启动速度
13 | 热点问题答疑(1):如何学习源码?
模块三 连接器 (9讲)
14 | NioEndpoint组件:Tomcat如何实现非阻塞I/O?
15 | Nio2Endpoint组件:Tomcat如何实现异步I/O?
16 | AprEndpoint组件:Tomcat APR提高I/O性能的秘密
17 | Executor组件:Tomcat如何扩展Java线程池?
18 | 新特性:Tomcat如何支持WebSocket?
19 | 比较:Jetty的线程策略EatWhatYouKill
20 | 总结:Tomcat和Jetty中的对象池技术
21 | 总结:Tomcat和Jetty的高性能、高并发之道
22 | 热点问题答疑(2):内核如何阻塞与唤醒进程?
模块四 容器 (8讲)
23 | Host容器:Tomcat如何实现热部署和热加载?
24 | Context容器(上):Tomcat如何打破双亲委托机制?
25 | Context容器(中):Tomcat如何隔离Web应用?
26 | Context容器(下):Tomcat如何实现Servlet规范?
27 | 新特性:Tomcat如何支持异步Servlet?
28 | 新特性:Spring Boot如何使用内嵌式的Tomcat和Jetty?
29 | 比较:Jetty如何实现具有上下文信息的责任链?
30 | 热点问题答疑(3):Spring框架中的设计模式
模块五 通用组件 (4讲)
31 | Logger组件:Tomcat的日志框架及实战
32 | Manager组件:Tomcat的Session管理机制解析
33 | Cluster组件:Tomcat的集群通信原理
特别放送 | 如何持续保持对学习的兴趣?
模块六 性能优化 (8讲)
34 | JVM GC原理及调优的基本思路
35 | 如何监控Tomcat的性能?
36 | Tomcat I/O和线程池的并发调优
37 | Tomcat内存溢出的原因分析及调优
38 | Tomcat拒绝连接原因分析及网络优化
39 | Tomcat进程占用CPU过高怎么办?
40 | 谈谈Jetty性能调优的思路
41 | 热点问题答疑(4): Tomcat和Jetty有哪些不同?
结束语 (1讲)
结束语 | 静下心来,品味经典
深入拆解Tomcat & Jetty
登录|注册

07 | Tomcat如何实现一键式启停?

李号双 2019-05-25
通过前面的学习,相信你对 Tomcat 的架构已经有所了解,知道了 Tomcat 都有哪些组件,组件之间是什么样的关系,以及 Tomcat 是怎么处理一个 HTTP 请求的。下面我们通过一张简化的类图来回顾一下,从图上你可以看到各种组件的层次关系,图中的虚线表示一个请求在 Tomcat 中流转的过程。
上面这张图描述了组件之间的静态关系,如果想让一个系统能够对外提供服务,我们需要创建、组装并启动这些组件;在服务停止的时候,我们还需要释放资源,销毁这些组件,因此这是一个动态的过程。也就是说,Tomcat 需要动态地管理这些组件的生命周期。
在我们实际的工作中,如果你需要设计一个比较大的系统或者框架时,你同样也需要考虑这几个问题:如何统一管理组件的创建、初始化、启动、停止和销毁?如何做到代码逻辑清晰?如何方便地添加或者删除组件?如何做到组件启动和停止不遗漏、不重复?
今天我们就来解决上面的问题,在这之前,先来看看组件之间的关系。如果你仔细分析过这些组件,可以发现它们具有两层关系。
第一层关系是组件有大有小,大组件管理小组件,比如 Server 管理 Service,Service 又管理连接器和容器。
第二层关系是组件有外有内,外层组件控制内层组件,比如连接器是外层组件,负责对外交流,外层组件调用内层组件完成业务功能。也就是说,请求的处理过程是由外层组件来驱动的。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Tomcat & Jetty 》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(37)

  • 一路远行
    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-26
    31
  • allean
    原理理解之后特别想看看源码是怎么写的,不看源码总感觉不踏实🤣,老师在介绍组件原理之后可不可以指明怎么启动Tomcat源码,并debug啊,多谢

    作者回复: 建议跟SpringBoot那样,用嵌入式方式启动Tomcat,这里有例子:
    https://github.com/heroku/devcenter-embedded-tomcat

    2019-05-25
    2
    20
  • yi_jun
    看了这篇文章对tomcat中用到的设计模式又有了新的理解.
    看到评论里有问tomcat启动的同学, 和大家分享一篇介绍Tomcat启动的文章, 从startup.bat的源码开始分析的.
    https://www.cnblogs.com/tanshaoshenghao/p/10932306.html
    2019-05-27
    9
  • 疯狂咸鱼
    老师,会不会考虑出一门课:深入拆解spring?我特别想听老师讲Spring架构的的设计,和里面用到的设计模式

    作者回复: 掌握了分析源码的方法,再分析Spring都不是难事。

    2019-06-02
    8
  • Monday
    思考题
    1,容器的创建/初始化/销毁
    2,容器添加/删除子容器
    3,如果还要监听容器状态变化的话还需要有添加/移除事件的方法。
    请指正。

    本节收获,干货干货。
    多种设计模式还带Tomcat设计的应用场景,面试设计模式绝对加分项(我还没消化)

    问题:进入架构篇,就处于下面这种学习状态。
    1,觉得老师讲得很有道理
    2,被动的吸收着知识点,没有自己的思路
    3,一看文档就感觉自己似乎是懂了,因为提不出好问题,一合上文档就感觉本节我没来过
    老师有没有好的建议,谢谢!

    作者回复: 你思考题回答的不错啊,还可以想想实际工作中是不是也有类似的场景,可以模仿这种设计。

    2019-05-25
    7
  • -W.LI-
    老师好!之前设计模式看过好几遍,总感觉用不上,虽然知道是自己对设计思想的理解不够深入导致的。又苦于找不到方法,看了老师的分析对设计模式,和设计原则又有了进一步的了解。问题1:对于变于不变的界定标准,哪些方法需要抽象为接口。老师有啥好的建议么。问题2:spring的event,发布一个事件时会把事件放入map.然后轮训所有的所有的观察者。观察者和event很多的时候,内存等开销,会成为性能瓶颈么?比如处理事件的逻辑比较复杂或者需要IO操作。会有处理速度跟不上事件发生的速度这样的情况导致OOM的么?

    作者回复: 1.这个要根据具体场景来的,简单来说如果你需要用if-else来实现某个逻辑,这是可能是变化点。
    2.这种情况下,对event的处理考虑用线程池。

    2019-05-25
    5
  • 刘冬
    老师太拼了,周末凌晨发新的课程。太感动了😹
    2019-05-25
    1
    5
  • nsn_huang
    这是Tomcat8.5版本的源码,基于Maven和IDEA,希望大家一起学习,一起进步。https://blog.csdn.net/sougou_1323/article/details/90597079

    作者回复: 谢谢分享!

    2019-05-27
    4
  • WL
    请问一下老师Tomcat为什么要在LifeCycleBase中定义一系列的***internal()让子类取调用, 为什么不是子类实现接口的init()方法呢, 这一点我不是很理解, 希望老师指点一下.

    作者回复: init方法里有一些”通用的逻辑“对各个子类都适用,如果让每个子类都重复实现一编,代码不久重复了吗,于是这些”逻辑“让LifeCycleBase来做,其实就是实现了模板,子类再在这个模板上填充自己的内容。

    2019-05-26
    4
  • 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-30
    3
  • QQ怪
    还好订阅老师专栏之前看完大话设计模式,正好根据tomcat原理来体会设计模式的精髓,不然都会看不懂啊,哈哈哈

    作者回复: 😑

    2019-05-26
    3
  • 飞翔
    老师 我从 tomcat class 里边的main方法找,跟踪到 catalina里边的load方法,在这个方法里边有digester.parse(inputSource); 我觉得这个应该是具体读serverxml的,但是在往下跟踪始终找不到哪里读server.xml 实例化server等,求指导

    作者回复: 可以在Server的构造函数里下断点,你会发现是XML解析器通过反射创建的

    2019-07-15
    2
  • Geek_ebda96
    老师,你的意思是配置在server.xml里的connector的线程池是tomcat对于一个应用的全局线程池,用于接受请求的socketprocessor会放到这个线程池里,假如这个应用里面有后台一些定时job或或其他需要异步线程处理的业务,也会从这个大的线程池里取线程处理,不会再单独做新建线程?

    作者回复: Connector上的线程池负责处理这个它所接收到的所有请求。一个Connector有一个线程池。

    其他的后台任务也有专门的线程池,不会占用Connector的线程池。

    2019-06-06
    2
  • 刘冬
    强烈呼吁老师能够讲解一下,怎么启动Tomcat的源码、调试。怎么读源码。
    另外,有些Interface的实现是在单独的Jar中,用Intellij无法直接看到Implementation,请问有什么好的办法看到这部分的源码吗?

    作者回复: 建议用嵌入式的方式来启动Tomcat。这里有个例子:

    https://github.com/heroku/devcenter-embedded-tomcat

    2019-05-26
    2
  • 空知
    老师,请教下
    两层关系决定了 组件由内到外 有小到大的加载顺序,这个地方为啥不是先外再内 先大再小,上层加载好了之后根据配置去加载子(内)组件?

    作者回复: 因为大组件包含小组件,小组件本身就是大组件的一部分,小组件不创建好,大组件是不能工作的。

    2019-05-25
    2
  • dingdongfm
    请问tomcat什么时候会reload?

    作者回复: 当Web应用文件发生变化的时候。

    2019-06-11
    1
  • K.Zhou
    这篇干货十足,几种设计模式的经典实际运用!
    2019-05-25
    1
  • 飞翔
    老师 求教 为什么lifecycleListeners 要用copyOnwritearraylist呢, 什么情况如果用普通list 会有并发问题?
    public abstract class LifecycleBase implements Lifecycle {
        private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();
    2019-10-24
  • 来碗绿豆汤
    老师啥时候出一个spring的课程啊,好喜欢你的讲课风格
    2019-10-03
  • 莫问
    讲得很不错
    2019-09-13
收起评论
37
返回
顶部