前面好几篇都说的是一个请求是怎么到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过程。

知识小罐头08(tomcat8启动源码分析 上)的更多相关文章

  1. 知识小罐头05(tomcat8请求源码分析 上)

    这一篇我们不看源码,就大概理一下Tomcat内部组成部分!前面花费了两篇博客的篇幅来说说了一般的maven web项目并部署到tomcat运行,其实都是为这篇做铺垫的! 其实我下载了tomcat7,t ...

  2. 知识小罐头09(tomcat8启动源码分析 下)

    初始化已经完成,现在就是启动这些组件,Tomcat中的start方法就是用于启动的,其实start的原理还是和上一篇说的初始化几乎一样!这里我就大概说一下,看几个比较关键的地方就行了. 前面的步骤就大 ...

  3. RocketMQ中Broker的启动源码分析(一)

    在RocketMQ中,使用BrokerStartup作为启动类,相较于NameServer的启动,Broker作为RocketMQ的核心可复杂得多 [RocketMQ中NameServer的启动源码分 ...

  4. RocketMQ中Broker的启动源码分析(二)

    接着上一篇博客  [RocketMQ中Broker的启动源码分析(一)] 在完成准备工作后,调用start方法: public static BrokerController start(Broker ...

  5. RocketMQ中PullConsumer的启动源码分析

    通过DefaultMQPullConsumer作为默认实现,这里的启动过程和Producer很相似,但相比复杂一些 [RocketMQ中Producer的启动源码分析] DefaultMQPullCo ...

  6. Django如何启动源码分析

    Django如何启动源码分析 启动 我们启动Django是通过python manage.py runsever的命令 解决 这句话就是执行manage.py文件,并在命令行发送一个runsever字 ...

  7. 知识小罐头07(tomcat8请求源码分析 下)

    感觉最近想偷懒了,哎,强迫自己也要写点东西,偷懒可是会上瘾的,嘿嘿!一有写博客的想法要赶紧行动起来,养成良好的习惯. ok,继续上一篇所说的一些东西,上一篇说到Connector包装了那两个对象,最后 ...

  8. 【Netty之旅四】你一定看得懂的Netty客户端启动源码分析!

    前言 前面小飞已经讲解了NIO和Netty服务端启动,这一讲是Client的启动过程. 源码系列的文章依旧还是遵循大白话+画图的风格来讲解,本文Netty源码及以后的文章版本都基于:4.1.22.Fi ...

  9. Quartz源码——scheduler.start()启动源码分析(二)

    scheduler.start()是Quartz的启动方式!下面进行分析,方便自己查看! 我都是分析的jobStore 方式为jdbc的SimpleTrigger!RAM的方式类似分析方式! Quar ...

随机推荐

  1. baseFileWriter.go

    package blog4go import ( "fmt" "os" "sync" "time" ) const ( ...

  2. bzoj2806 [Ctsc2012]Cheat

    我们的目的就是找到一个最大的L0,使得该串的90%可以被分成若干长度>L0的字典串中的子串. 明显可以二分答案,对于二分的每个mid 我们考虑dp:f[i]表示前i个字符,最多能匹配上多少个字符 ...

  3. oracle服务的一些问题,先发2个,以后慢慢添加~~

    OracleOraDb11g_home1TNSLister服务启动后停止 解决办法: 1. 修改文件C:\app\zhuwei\product\11.1.0\db_1\NETWORK\ADMIN\li ...

  4. zookeeper配置管理+集群管理实战

    引言 之前就了解过kafka,看的似懂非懂,最近项目组中引入了kafka,刚好接着这个机会再次学习下. Kafka在很多公司被用作分布式高性能消息队列,kafka之前我只用过redis的list来做简 ...

  5. [译] 理解 LSTM 网络

    原文链接:http://colah.github.io/posts/2015-08-Understanding-LSTMs/ 吴恩达版:http://www.ai-start.com/dl2017/h ...

  6. vue+axios访问本地json数据踩坑点

    当我们想在vue项目中模拟后台接口访问json数据时,我们发现无论如何也访问不到本地的json数据. 注意:1.在vue-cli项目中,我们静态资源只能放在static文件夹中,axios使用get请 ...

  7. window.history.back(-1);与window.go(-1);的区别

    history.back(-1):直接返回当前页的上一页,数据全部消息,是个新页面 history.go(-1):也是返回当前页的上一页,不过表单里的数据全部还在 history.back(1) 前进 ...

  8. shell简明教程

    shell的格式 shell可以在直接在命令行下输入,也可以保存成shell脚本文件运行.当命令简单并且不需要重复使用,在命令行输入直接执行即可,否则就写成脚本.shell脚本默认文件扩展名为.sh. ...

  9. Airtest 快速上手教程

    一.Airtest 简介: AirtestIDE 是一个跨平台的UI自动化测试编辑器,适用于游戏和App. 自动化脚本录制.一键回放.报告查看,轻而易举实现自动化测试流程 支持基于图像识别的 Airt ...

  10. HSTS 详解,让 HTTPS 更安全

    随着互联网的快速发展,人们在生活中越来越离不开互联网.无论是社交.购物还是搜索,互联网都能给人带来很多的便捷.与此同时,由于用户对网络安全的不了解和一些网站.协议的安全漏洞,让很多用户的个人信息数据“ ...