[图片] 开头说两句 小刀博客: https://www.lixiang.red 小刀公众号: 程序员学习大本营 学习背景 在前面几篇文章, 我们一起学习了 tomcat 中的 server.xml , 类加载器, 组件默认值,digester 解析 server.xml 并初步初始化等基础知识点 https://ww ..

tomcat 学习 |tomcat 中组件结构设计

开头说两句

小刀博客: https://www.lixiang.red
小刀公众号: 程序员学习大本营

学习背景

在前面几篇文章, 我们一起学习了 tomcat 中的 server.xml , 类加载器, 组件默认值,digester 解析 server.xml 并初步初始化等基础知识点
https://www.lixiang.red/articles/2019/08/11/1565515601658.html
下面我们就要真正的走进源码, 去看一看这些组件是如何实现的, 今天我们一起学习 tomcat 中组件的设计

源码中的这些组件

通过下图我们可以看到, 在我们直接使用的 Context,Service,Server 上面还有一层接口: Container 和 Lifecycle
image.png
我们说接口是有什么什么能力, 现在我们就整理下这些组件的接口
以内层的 Context 为例, 我们在 idea 中可以看到如下继承图:
image.png
同样, 我们去对比其他的组件, 也会发现他们都类似于继承这些接口, 几大常用组件的继承关系如下所示:
image.png
我们可以通过 idea 的类图工具, 查看类的继承以集接口相关的方法, 对着类名点右键, 然后可以看到相关的图
image.png
image.png

Lifecycle 接口

我们可以对上图中的接口做一个划分, 如下所示
image.png
上面三个方法是 Listener 相关的
中间三个方法是自身生命周期相关的
下面两个方法是获取自身状态的

listener

监听器, 每一组件, 有一组监听器, 在组件本身达到某一状态时, 可以循环监听器 list , 然后这些注册监听器的组件, 再根据监听到的状态进行相关的动作行为.
我们以 server 为例:
image.png

 /**
     * 循环监听器List , 去执行不同的动作
     *
     * @param type  Event type
     * @param data  Data associated with event.
     */
    protected void fireLifecycleEvent(String type, Object data) {
        LifecycleEvent event = new LifecycleEvent(this, type, data);
        for (LifecycleListener listener : lifecycleListeners) {
            listener.lifecycleEvent(event);
        }
    }

当执行 server 的 start 时, 就会去向所有的监听器传播 CONFIGURE_START_EVENT 这个事件. 但是监听器对这个事件做不做响应, 就是对应的实际监听器所做的决定, 如下图所示,HostConfig , 在接收到事件时, 要判断类型, 对不同类型的事件, 做不同的处理. 基本上 Config 都继承了 LifecycleListener 这个接口
image.png

组件本身的生命周期

中间四个方法, 代表着组件的四种状态:init(), 初始化, start() 启动,stop()停止,destory( 销毁), 这些通过字面意思就能猜出来.tomcat 官方给了一张生命周期和状态对应的流程图:
image.png
重点不在于上面的图, 而在于下面话, 组件通过调用不同的方法, 使自身达到不同的状态, 然后调用监听器 list , 去通知其他的组件 / 配置做相应的处理, 以 Server 这个组件为例:, 在前几篇中, 我们讲 tomcat 启动流程的时候, 分析到这里, 会调用 server.init(), 实际上就是调用了生命周期的第一个阶段方法
image.png
我们可以看到, init 执行的 LifecycleBase 类中的 init 方法, 最终, 是执行的 StandardServer 中的 initInternal 方法,
image.png

	// 初始化我们的service 
        for (int i = 0; i < services.length; i++) {
            services[i].init();
        }

同样, 我们可以去看到,start 也是一个类似的过程, 所以这四个方法, 是贯穿整个 tomcat 生命周期的, 推动着 tomcat 的运行

本身状态

可以通过下图看使用方法: 组件.getState().isAvailable(), 去判断组件是否在可用状态, 通过 LifecycleState 源码可以看到, 只在三种状态下 available 是可用的

image.png

STARTING(true, Lifecycle.START_EVENT),
    STARTED(true, Lifecycle.AFTER_START_EVENT),
    STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),

Container 接口,pipeline,valve

通过其名字, 我们可以大致猜测, 是表示一个容器, 那么做为一个容器, 他有自己的名字, 有子容器 (Children), 但是这些容器本身并没有处理业务逻辑的功能, 所以, 一个容器还会绑定一个执行链.
Tomcat 中定义了 Pipeline, valve 来帮助 Container 来处理业务, 每个 Container 组件通过执行一个 pipeline 里面的 valve 来执行业务. 对于每个容器, 都会有一个默认的 valve 在最底层, 最后来执行. 如果用户 / 使用者没有自定义的话, 就会使用默认的.
我们可以看到在 valve 的方法中, invoke 方法, 已经是和业务 / 具体处理是相关联的了
image.png
我们以 StandardEngineValve 为例, 可以看到, 对于同一个 request 和 response, 他在 Invoke 方法中, 又调用了 host 的 valve 的 inove

@Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {

        // Select the Host to be used for this Request
        Host host = request.getHost();
        if (host == null) {
            response.sendError
                (HttpServletResponse.SC_BAD_REQUEST,
                 sm.getString("standardEngine.noHost",
                              request.getServerName()));
            return;
        }
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(host.getPipeline().isAsyncSupported());
        }

        // 调用host的valve去继续处理request,response
        host.getPipeline().getFirst().invoke(request, response);

    }

后面我们学习也就是以对 request, response 的处理为主

最后说两句

今天我们学习的 tomcat 组件的接口结构, 是后面学习的基础, 在学习过程中, 小伙伴们有什么问题, 可以和小刀一起交流:best396975802

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    2266 引用 • 7668 回帖 • 929 关注
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    135 引用 • 515 回帖
回帖   
请输入回帖内容...