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
tomcat学习|tomcat中组件结构设计
我们说接口是有什么什么能力,现在我们就整理下这些组件的接口

以内层的Context为例,我们在idea中可以看到如下继承图:
tomcat学习|tomcat中组件结构设计
同样,我们去对比其他的组件,也会发现他们都类似于继承这些接口,几大常用组件的继承关系如下所示:
tomcat学习|tomcat中组件结构设计
tomcat学习|tomcat中组件结构设计

我们可以通过idea的类图工具,查看类的继承以集接口相关的方法,对着类名点右键,然后可以看到相关的图

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

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

Lifecycle接口


我们可以对上图中的接口做一个划分,如下所示

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

上面三个方法是 Listener相关的
中间三个方法是自身生命周期相关的
下面两个方法是获取自身状态的

listener


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

 /**
     * 循环监听器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 这个接

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

组件本身的生命周期

中间四个方法,代表着组件的四种状态:init(),初始化, start() 启动,stop()停止,destory(销毁),这些通过字面意思就能猜出来.tomcat官方给了一张生命周期和状态对应的流程图:

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

重点不在于上面的图,而在于下面话,组件通过调用不同的方法,使自身达到不同的状态,然后调用监听器list , 去通知其他的组件/配置做相应的处理,以Server 这个组件为例:,在前几篇中,我们讲tomcat 启动流程的时候,分析到这里, 会调用server.init(),实际上就是调用了生命周期的第一个阶段方法
tomcat学习|tomcat中组件结构设计
我们可以看到, init执行的LifecycleBase类中的init方法,最终,是执行的StandardServer中的initInternal方法,
tomcat学习|tomcat中组件结构设计


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

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

本身状态


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

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

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方法,已经是和业务/具体处理是相关联的了
tomcat学习|tomcat中组件结构设计
我们以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组件的接口结构,是后面学习的基础,在学习过程中,小伙伴们有什么问题

猜你喜欢

转载自blog.51cto.com/15082395/2647299