• 知识小罐头08(tomcat8启动源码分析 上)


      前面好几篇都说的是一个请求是怎么到servlet中的service方法的,这一篇我们来看看Tomcat8是怎么启动并且初始化其中的组件的?

      相信看了前面几篇的小伙伴应该对Tomcat中的各个组件不陌生了,所以我们就可以加快一点速度;

      简单说一下Tomcat启动流程,首先是设置一下各种类加载器,然后加载server.xml配置文件,然后初始化Container各个容器,最后就是连接器Connector。

    1.批处理文件  

      双击startup.bat文件启动tomcat,其实内部就是跳转到catalina.bat文件(.bat文件时windows系统用的,那些.sh配置文件是Unix、Linux系统使用的)

      startup.bat文件内部其实就是一些指令从上到下顺序执行,作用是进行一些目录的判断,并找到catalina.bat文件的位置,如下图所示

       注意:.bat文件其实就是一个批处理文件,里面一条条的命令都有自己独特的语法,你知需要百度“startup.bat详解”可以看到很多博客,其实就我感觉很像mysql的触发器吧,里面封装了很多命令,有自己独特的语法,只要一触发就会一连串的执行,这里就不多说,不是我们的重点,用到的时候再去仔细研究,这里粗略提一下。

      

       我们再看看catalina.bat文件 

       由于tomcat是用java语言开发出来的,所以启动Tomcat本质上就是运行一个java程序的main方法,然后后续就会初始化一系列的东西。

    2.看看Bootstrap类的main方法

      我们就看看main方法内核心部分,在下图中标识了三步:

     

      总结一下,main方法内部核心就是创建一个Bootstrap对象,然后调用这个对象的init、load、start方法,看名字就应该大概猜出一点东西了:

      init:大概是初始化一些类加载器什么的;

      load:应该是加载什么配置文件,还记得我说过最重要的配置文件是哪个吗?对,就是server.xml文件,其实就是加载这个文件;

      start:内部差不多初始化完了所有的容器和连接器,等待连接;

      我们分别对这三个方法加断点进行调试,理解其中的原理之后整个Tomcat的启动流程也就清楚了!

    3.init方法

      还是只看核心的逻辑,至于怎么实例化类加载器和设置类加载器,感兴趣的小伙伴就自己去研究走走源码。

     4.load方法

      通过看源码,其实可以看到Bootstrap的load方法,就是通过反射调用Catalina的load方法

      我们断点进入最后的那个invoke方法,看看Catalina的load方法是加载了些什么东西

       这个Digester就是为了解析servler.xml定义了很多的解析规则,真要搞懂这个东西,肯定要花一定的时间去好好研究的;

      我们在这里简单而随意看几个我们熟悉的东西,具体的解析过程肯定要自己去了解的;

     

      这个Digester是了解servler.xml具体解析规则必要的东西,我们把规则已经指定好了,下一步肯定就是加载server.xml文件了

      准备好了Digester和server.xml的流之后,然后底层用SAX去解析这个xml文件(注意,前面只是解析出来了server.xml中的各个组件对应的类名以及组件之间的父子关系, 没有实例化,到parse方法才真正实例化

       接着我们就要去把一些需要用到的容器进行一些初始化设置,更方便我们使用!

      从这里开始我们就会看到一个类似多米诺骨牌效应的这么一个现象,一个接一个的初始化,而且这里涉及到了一个知识点叫做JMX,有关于这个JMX(Java Management Extensions),我查了很多的资料,网上复制粘贴的一大堆,看得很乱,虽然我没有怎么仔细的去研究,但是大概的逻辑我是知道了,下面就简单的说说;

    5.JMX的简介和事件监听

      便于理解,JMX可以想象成工商局,每家公司必须要向工商局注册自己,这个时候工商局就对每一家公司都有了管理的权利,无论是哪一家公司要改名字,要合并,注销等等,都必须经过工商局的的同意,工商局还能对一些非法公司进行整改什么的,可以说工商局就是管理了每一家公司的生命周期,可以对每家公司进行监控符合管理。

      对应在Tomcat中,我们必须要把Tomcat中的所有组件(在这里叫做MBean,类似spring容器中叫做bean)给注册到一个叫做Registry的地方,Registry就是基于JMX搞出来的一个东西,然后我们执行所有组件的init,start方法,都可以在JMX中找到对应的MBean执行对应的init、start方法;这里也只是稍微提一下JMX,内容很多一下子说不完,最好自己多查查资料看看。

     

      JMX的结构图找了好久,终于看到一个图比较满意的,进行一些小小的修改,如下所示:

      Agent Layer(代理层):主要包括Agent Services中几个服务(计时器、监控、动态加载MBean、关系服务),还有MBean Server两部分组成

      Distributed layer(分布层):包含一些比较厉害的组件,其实我感觉就类似可视化工具,可以很方便的对那些MBean进行一些管理和修改。

      还有在MBean Server中的多个MBean组成一个Instrumentation Layer(指示层),这个就没啥说的;总之,JMX我用得不是很多,需要真正用到的时候再慢慢研究吧,哈哈!

      感兴趣的小伙伴可以自己研究这个写几个HelloWorldMBean试试就ok了

       

      再说说事件监听,事件监听又是一个什么鬼呢?不准确的来说,在Tomcat启动的时候会有个全局事件(就类似一个全局变量),很多的监听器会时时刻刻监听这个全局事件,当对一个组件进行一些操作(会修改状态码state),那么这个全局事件就会变化,遍历所有监听器执行某方法,下面就随便看看这个全局事件:

     还记得最前面的server.xml配置文件的<server>中配置的很多监听器吗?其实就是配合这个全局事件起作用的(看英文应该翻译成生命周期事件吧。。。)

     6.接第4步继续

      这里一定要理清楚一个逻辑,Tomcat中所有组件都必须是LifecycleBase的子类(其实都直接或者间接的继承了LifecycleBase这个类),这个类就是所有组件的爸爸,假如这个爸爸有九个儿子,大儿子要给最小的儿子一颗糖,你就会看到一个很有趣很坑爹的现象:大儿子-------->爸爸---------->二儿子--------->爸爸--------->三儿子---------->爸爸---------->四儿子---------->.......------->爸爸------->最小的儿子!

      这样糖才能到最小的儿子手里,是不是真的很坑爹,哈哈!

      所以我们在Tomcat也可以看到一个这样的逻辑:

      server.init()---------->LifecycleBase.init(), 在init()方法内部就会执行initInternal()方法,并改变全局事件------------->server中的initInternal()方法 ,内部执行service.init()方法------------>LifecycleBase.init(),执行initInternal()方法,并改变全局事件--------->service中的initInternal()方法,内部就是connector.init()和engine.init()---------->LifecycleBase.init()。。。。。后面都是这个逻辑,几乎一模一样,初始化之后启动start()的逻辑也是这个,所以这个逻辑一定要搞清楚,搞清楚这个了后面就没难度了。

      下面我们就简单看看一些关键的地方,由于绝大部分都是相同的,就不一一截图了;

      看看initInternal()方法内部:

      一直往下看,我们看看StandardService中的initInternal()方法:

      engine的初始化是在看不出来什么有趣的东西,我们就重点看看HTTP连接器的初始化的关键代码:

       【省略很多重复步骤】

     

       【省略很多重复步骤】

      这个是Tomcat的NIO连接,其中addr=0.0.0.0/0.0.0.0:8080;acceptCount = 100;看这个就知道监听8080端口,默认并发连接数100个,这个可以自己根据实际情况设置

      到这里Tomcat启动初始化的步骤算是结束了,内容看起来比较多,但是思路自我感觉还是比较清晰的,了解JMX和事件监听的相关知识之后,还是比较容易的,不过强调一点,一定要自己走走源码,加深理解!

      这篇说的东西不多,就是初始化了几乎所有组件,就好像一个厨师,把所有的菜都洗好并且切好、分类、分盘,调料也准备就绪,下一步,就是开始做出美味的菜肴了。

      下一篇我们简单看看Tomcat的start过程。

  • 相关阅读:
    win10安装.net3.5
    VS2015密钥
    wordpress目录文件结构说明
    js | javascript获取和设置元素的属性
    wordpress | WP Mail SMTP使用QQ邮箱发布失败的解决办法
    jquery 实时监听输入框值变化方法
    XPath编写规则学习
    如何将portfolio产品图片上的悬停去掉?
    wordpress怎么禁止文章复制
    js | javascript实现浏览器窗口大小被改变时触发事件的方法
  • 原文地址:https://www.cnblogs.com/wyq1995/p/10165874.html
Copyright © 2020-2023  润新知