• Tomcat8源码笔记(五)组件Container分析


    Tomcat8源码笔记(四)Server和Service初始化 介绍过Tomcat中Service的初始化 最先初始化就是Container,而Container初始化过程是咋样的?

     

    说到Container的初始化,Tomcat8源码笔记(三)Catalina加载过程 这篇文章记录了Tomcat是怎样解析server.xml的流程,再此基础上,我们来分析Container的初始化。

    这是Catalina定义的解析规则,之前都是添加的Rule接口的实现,而RuleSet可以理解为一堆Rule更具象的接口;而各种各样的Rule作用是啥,目的就是解析server.xml时候,按照规则来解析并且生成有结构的对象。

    image

    Digester的addRuleSet方法:

    因为Tomcat  server.xml没有用到DTD XSD文件声明元素,所以namespaceURI都是null(我是这样理解的),所以添加RuleSet类型的规则实际上是调用ruleSet的addRuleInstances方法.那就来记录下EngineRuleSet的addRuleInstances方法。

    image

    Engine元素规则

      这些规则ObjectCreate、SetProperties、SetNext分别有啥用,Tomcat8源码笔记(三)Catalina加载过程 这里就不多介绍了;

    可以得出以下结论:Engine的实例化对象为StandardEngine,StandardEngine会有第一个监听器,EngineConfig,如果哪天不想添加EngineConfig作为第一个默认的监听器,方法也是可以的,修改Engine元素的engineConfigClass即可;   我们可给Engine元素添加这些子元素达到扩展的目的:Cluster、Listener、Valve、Realm,;

      其实总结下来就是,Engine容器具体实例化对象为StandardEngine,且天生自带监听器EngineConfig,且Engine的父容器就是StandardService

    image

      按照   Tomcat8源码笔记(三)Catalina加载过程 的说明,只是将StandardService调用了setContainer关联了StandardEngine,那是不是就像 Service是父母,而Engine是婴儿,父母知道婴儿是谁,但是婴儿却不知道父母是谁呢?  为了让Container容器知道父类Service是谁,实现方案也很简单:

       Tomcat在给Service设置容器的时候,顺便双向关联了Engine,这里也能看出来,Tomcat结构中Service的容器就是Engine!

    image

    其他属性先忽略,验证下我们得到的结论: 注意service以及lifecycleListener,可以验证我们上面的分析。

    image

    StandardEngine容器初始化

    按照之前 Tomcat8源码笔记(四)Server和Service初始化 分析的来看,StandardEngine初始化initInternal核心方法调用之前,触发监听器的before_init事件!

    https://img2018.cnblogs.com/blog/1550387/201904/1550387-20190406205000314-1326514266.png

    当然了 StandardEngine目前的listener也就是EngineConfig,它触发时间仅仅针对 StandardEngine的start、stop方法才做逻辑处理,所以此处忽略其触发监听器before_init和after_init事件

    image

    那StandardEngine初始化的真正方法initInternal做了什么处理?

    getRealm方法只是为了确保realm属性的存在,哪怕没有Realm子元素,我也给你一个NullRealm;

    super.initInternal在抽象类LifecycleMBeanBase的子类中,调用父类initInternal,是为了JMX注册,比如StandardEngine、StandardService都是为了JMX注册;

    而到了容器这里,super.initInternal又进行了额外的处理,可以看成是容器特有的,和服务区分开来。

    image

    IDEA给我们绘制的Tomcat组件结构中,可以看到LifecycleMBeanBase子类又抽象出ContainerBase,ContainerBase的initInternal方法又是一番逻辑!

    image

    ContainerBase的initInternal

    可以看到初始化了一个ThreadPoolExecutor,corePoolSize和maxPoolSize默认都是1,线程名字前缀为getName()+”-startStop-”,比如StandardEngine,线程名字就是

    Catalina-startStop-1这种模式。 之后才是用父类LifecycleMBeanBase的initInternal注册JMX中.

    image

    继续回到StandardService的初始化,Tomcat8源码笔记(四)Server和Service初始化  container已经初始化完毕,而executor、mapperListener的初始化工作除了JMX之外,没任何操作了,这两个组件真正起作用是在start启动中;后面文章就以Tomcat核心组件Connector初始化来分析。

    image

    补充于2019.4.9

    StandardEngine的实例化,这么重要的居然忘记记录了!

    Tomcat中容器的实例化基本都是通过空参构造器反射实例化,暂时未见到例外;查看StandardEngine的空参构造器

    image

    这里就不得不记录一个重要的接口Pipeline的分析

    Pipeline接口所有方法围绕着Valve和Container有关,

    image

     

    Valve接口

    Valve接口有点像链表,我可以获取我下一个指向的链表; Valve接口还定义了invoke方法; 按照英语翻译Valve是阀门的意思,而Pipeline是管道的意思;

    image

     

    上面接口介绍有点抽象,直接来看下StandardEngine中的管道和阀门吧; 首先pipeline的初始化不是在StandardEngine中,而是在ContainerBase中:实例化Pipeline实现类,并且调用setContainer将容器和Pipeline关联在一起。

    image

     

    而StandardEngine初始化过程中就使用了pipeline.setBasic方法,我们来看下setBasic方法:

    setBasic方法设置了pipeline的basic,并且如果原来pipeline存在first,first下一个指向原来的basic,那现在basic是新添加的valve,且原来的basic的next就是添加进来的valve.

    image

     

     

     

     

     

     

     

  • 相关阅读:
    python基本数据类型(—)
    linux基本命令
    1、认识Mysql
    Flask-SQLAlchemy详解
    sqlalchemy基本增删改查
    pymongo方法详解
    uWSGI+Nginx部署
    uwsgi
    nginx负载均衡配置
    redis-sentinel主从复制高可用(哨兵)
  • 原文地址:https://www.cnblogs.com/lvbinbin2yujie/p/10674140.html
Copyright © 2020-2023  润新知