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

本贴最后更新于 1958 天前,其中的信息可能已经沧海桑田

开头说两句

小刀博客: 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 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3190 引用 • 8214 回帖 • 1 关注
  • Tomcat

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

    162 引用 • 529 回帖 • 4 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...