Tomcat8源码笔记(七)组件启动Server Service Engine Host启动
一.Tomcat启动的入口
Tomcat初始化简单流程前面博客介绍了一遍,组件除了StandardHost都有博客,欢迎大家指文中错误。Tomcat启动类是Bootstrap,而启动容器启动入口位于 Catalina 的start方法: 因为反射调用Bootstrap的Catalina实例的start方法.
Catalina启动分为两个大阶段,一是启动Server(start方法),二是 Server启动之后等待(await方法)
一.StandardServer#start
按照之前记录 Tomcat8源码笔记(一)Lifecycle接口 Tomcat的初始化 init 、启动 start都是采用模板设计模式, 共性的地方就是触发监听的事件,个性的地方就是 initInternal、startInternal ,
StandardServer初始化默认是六个监听器,Tomcat8源码笔记(四)Server和Service初始化 这六个监听器暂且就不记录, 直接查看StandardServer的 startInternal方法.
StandardServer#startInternal解读:首先触发configure_start监听事件,主要是完成NamingContextListener的相关JNDI操作,这个暂且忽略. 设置StandardServer状态进入启动中LifecycleState.STARTING,同样六个触发监听器中相关事件; globalNamingResources同样是Tomcat组件,实现Lifecycle接口,所以globalNamingResources#start也会按照模板方法来,具体干嘛的还不清楚,后面补充; 最核心的地方看到了,StandardServer的初始化交给了Service的start,遍历Server的Service,分别start.
二.StandardService#start
StandardService默认是没有监听器的,所以start模板方法直接看startInternal即可. Tomcat8源码笔记(四)Server和Service初始化 这里介绍过StandardService的初始化,可以证明.
StandardService的startInternal方法按顺序分为四个步骤:启动容器container(通常就是StandardEngine)、启动线程池executor、启动mapperListener、启动connector连接器.
那我们下面就从container, 也就是StandardEngine 启动开始记录.
三. StandardEngine#start
Tomcat8源码笔记(五)组件Container分析 记录过StandardEngine的实例化包括初始化过程,StandardEngine有一个监听器,是Tomcat为我们注册的 EngineConfig.
EngineConfig的lifecycleEvent方法如下: 可以看到EngineConfig的start时机是容器启动staring状态,而StandardEngine一开始启动进入的状态是before_start.
StandardEngine#startInternal如下: 可以看到除了打印日志Starting Servlet Engine以外,就是调用父类的startInternal方法;而StandardEngine的父类是ContainerBase,不是LifecycleMBean这个啥,所以StandardEngine启动核心在ContainerBase中.
ContainerBase#startInternal方法
ContainerBase#startInternal方法,Cluster默认的server.xml中没有配置为空,Realm默认的server.xml中配置了一个LockOutRealm,Realm作为一个组件,start方法又是一遍Tomcat的流程,这里重点不是记这个; StandardEngine的children也就是StandardHost,startStopExecutor在之前介绍的Tomcat8源码笔记(五)组件Container分析 中初始化过了,初始化方法位于ContainerBase#initInternal。 这里可以看到使用线程池执行了StartChild实例,StartChild持有当前StandardHost对象,下面程序会阻塞着,直到StartChild的call执行完毕,程序执行完StartChild,还会调用Pipeline的start,启动自身的后台线程。 startInternal执行逻辑有点多,我们先从StartChild看起!
三.一 StartChild#call
因为StartChild是通过线程池来执行的,我们可以通过IDEA很方便的进行多线程DEBUG,这点我以前用Eclipse时候没发现这种优点!
多线程DEBUG方式,在StartChild#call处打断点,上面Suspend(挂起)地方勾选Thread,具体作用对我而言最明显的就是,有时候多线程DEBUG,不选Thread,线程切换时候IDEA界面在那里抽筋一样多个代码地方跳跃,很影响感受,F6单步调试按一下,屏幕狂跳一下.
切换线程的窗口位于DEBUG视图,下面红框的地方可以选择要调试哪个线程。 记住: StartChild执行的那个线程池出来的线程名字叫Catalina-startStop-,而1代表了线程的编号;另外也可以发现executor.submit(new StartChild())方法,得到的Future,在调用get方法之后会一直堵塞知道方法结束,下图中的main线程就在WAIT等待状态.
跑偏了,可以看到上面StartChild,因为StartChild持有StandardHost实例,call方法也是调用StandardHost#start方法! 而StandardHost组件初始化工作都没有做过,组件状态还是NEW的状态,所以按照Tomcat的start模板方法,会先init初始化,然后再start! StandardHost实例持有一个LifecycleListener :HostConfig,不用说肯定是Tomcat替我们注册的,就像StandardEngine有一个EngineConfig的监听器。
那下面的逻辑清楚了,StandardHost#start,先是触发HostConfig初始化事件监听---->StandardHost#initInternal—>HostConfig初始化结束事件监听---->HostConfig启动前事件监听--->
StandardHost#startInternal---->HostConfig启动结束事件监听.
三.二 HostConfig监听触发事件
可以看到只是给HostConfig设置四个 StandardHost的属性:copyXML、unpackWARs、deployXML、contextClass,另外触发事件只在before_start、start等情况下才有逻辑处理,所以before_init只是设置了上面四个属性而已。
按照上面流程,该是 StandardHost#initInternal:
转念一想,StandardHost继承自ContainerBase,initInternal方法应该也是初始化线程池,StandardEngine初始化的线程池产生的线程名字叫Catalina-startStop-,而StandardHost初始化的线程池产生线程名字类似 localhost-startStop-,此外的super.initInternal肯定就是JMX注册功能了.
继承走流程,该是HostConfig触发初始化结束after_init事件,但是上面有HostConfig触发代码,没有after_init的逻辑处理,所以呢?又重复设置了上面四个属性;
继续流程,HostConfig触发启动之前before_start事件,会调用HostConfig#beforeStart:
HostConfig#beforeStart
host#getCreateDirs默认返回true,host#getAppBaseFile获取到catalina-home/webapps目录,并赋值给StandardHost的appBaseFile,
host#getConfigBaseFile获取到catalina-home/conf/Catalina/localhost目录,并赋值给StandardHost的hostConfigBase,
之后校验这两层目录是否存在、是否是目录,属于校验目录是否存在为下面项目作保障。
继承走流程,StandardHost#startInternal, StandardHost在此之前Pipeline有两个Valve阀门,first是AccessLogValve,basic阀门是StandardHostValve,执行之后会添加一个阀门到first的next,这个阀门就是ErrorReportValve; 此外还会调用父类ContainerBase的startInternal方法. 父类ContainerBase#startInternal方法比较冗长,因为StandardHost没有子容器了,所以startInternal主要从Pipeline的start,到设置组件状态为STARTING,到启动自身守护线程;这里我们重点先关注,设置StandardHost状态为STARTING,这就又触发HostConfig的监听事件了!
HostConfig触发start监听事件,执行的方法是start,以下代码JMX忽略,那就是判断之前的appBaseFile是不是目录,deployOnStartup属性默认true,部署项目在TOMCAT启动的时候,那deployApps肯定就是部署项目了呗!先说好,按照上面流程分析,部署完项目之后呢,HostConfig的start就完事了,StandardHost的startInternal也就剩下启动自身守护线程没记录了,然后最后一步呢触发HostConfig启动完成监听,启动完成也没这种监听啊!所以当下只有deployApps和startThread了!
HostConfig#deployApps
deployApps除了前两行,我觉得每一个方法都是部署项目有关的,就是部署各种各样类型的项目呗!再来回忆杀下,appBase是catalina-home/webapps,configBase是catalina-home/conf/Catalina/localhost,至于这几个路径咋拼成的呢? catalina是StandardEngine的name,localhost是StandardHost的name.
filterAppPaths
unfilteredAppPaths就是webapps下所有文件名集合,说来也巧合我们StandardHost的deployIgnore,没设置过就是null,默认啥都不校验忽略;也告诉我们可以在server.xml中的Host元素里配置deployIgnore=“….”,来完成正则表达式匹配达到不部署某些项目的目的,学到了! 果然一个方法就是一个知识点啊!
deployDescriptors
deployDescriptors方法暂时不知道作用,后续补充!
deployWARs
代码过于长,这里不占用篇幅贴图了,主要适用于部署webapps下的 .war项目,后面会尝试部署一个war项目,暂时留作不记录,代码位置位于 HostConfig#deployWARs !
deployDirectories
这个适合我们分析,因为部署的都是文件夹型的项目,实例化了ContextName类,并且部署项目方式是线程池来执行DeployDirectory,并且会一直阻塞着直到webapps下目录项目都部署完毕,我们又可以使用IDEA多线程方式DEBUG
DeployDirectory类定义如下,我们在run方法中打上断点即可进入DEBUG,另外值得考虑的一点是?万一项目多,为啥Tomcatmore不是采用线程池,扩大一点线程数呢?我们可以看到StandardHost的初始化线程和最大线程数都是一致的,1个? 这是为什么呢?多线程可以加快部署项目速度吗?
在DEBUG之前,在补充一个类ContextName,baseName就是项目文件夹名字,path和name一般都是/文件夹名字,比如 /docs 、 /SpringWeb等等,而Root项目的path是“”,TOMCAT也是根据path来将我们的请求转发到对应项目中。
正式进入项目部署的环节,deployDirectory
代码比较冗长,这里只记录下过程,代码位置在:HostConfig#deployDirectory.
webapps下某个项目为例,假设WEB-INF下不存在content.xml,实例化一个StandardContext,代表一个项目,给StandardContext添加ContextConfig,并且给StandardContext设置ContextName的四个属性值,path、name、baseName、version等等,再将StandardContext加入到StandardHost; 部署完成之后就是存储在HostConfig的deployed中,稍后专门写一篇博客记录部署项目。
Tomcat部署项目打印日志如下:
部署完成webapps下的项目,程序会阻塞着直到项目都部署完成,至此HostConfig#start完成,StandardHost#start还剩下 threadStart方法
由于backgroudProcessorDelay默认设置为-1,所以并没有启动这个ContainerBackgroudProcessor!
至此,StandardHost启动完毕,再次回顾下,StandardHost的启动是通过线程池(线程初始化、最大个数都为1个的池子)来启动的,StandardHost可以说完成了webapps下项目的部署,
StandardEngine启动了StandardHost,创建了一堆StandardContext对应每一个项目,而ContainerBase的initInternal方法还没看完,还剩下三步:管道pipeline启动,设置状态为start触发相应监听,启动自身守护线程,会启动一个ContainerBackgroudProcessor线程!
至此StandardServer包括StandardService的启动完毕,也就意味着是Container的启动完毕,而Tomcat还没启动的就是mapperListener、Connector了,大体记录了一遍流程,篇幅原因还有的细节后面补充.
Tomcat8源码笔记(七)组件启动Server Service Engine Host启动的更多相关文章
- Tomcat8源码笔记(五)组件Container分析
Tomcat8源码笔记(四)Server和Service初始化 介绍过Tomcat中Service的初始化 最先初始化就是Container,而Container初始化过程是咋样的? 说到Contai ...
- Tomcat8源码笔记(九)组件StandardContext启动流程--未完待续
StandardContext代表的是webapps下项目,一个项目就是一个StandardContext,作为Tomcat组件的一部分,就会实现Lifecycle接口,被Tomcat管理着生命周期, ...
- Tomcat8源码笔记(八)明白Tomcat怎么部署webapps下项目
以前没想过这么个问题:Tomcat怎么处理webapps下项目,并且我访问浏览器ip: port/项目名/请求路径,以SSM为例,Tomcat怎么就能将请求找到项目呢,项目还是个文件夹类型的? Tom ...
- Tomcat8源码笔记(六)连接器Connector分析
根据 Tomcat8源码笔记(五)组件Container分析 前文分析,StandardService的初始化重心由 StandardEngine转移到了Connector的初始化,本篇记录下Conn ...
- Tomcat8源码笔记(四)Server和Service初始化
上一章 简单说明下Tomcat各个组件: Server:服务器,Tomcat服务器,一个Tomcat只有一个Server组件; Service:业务层,是Server下最大的子容器,一个Server可 ...
- Tomcat8源码笔记(三)Catalina加载过程
之前介绍过 Catalina加载过程是Bootstrap的load调用的 Tomcat8源码笔记(二)Bootstrap启动 按照Catalina的load过程,大致如下: 接下来一步步分析加载过程 ...
- Tomcat 启动时 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context}
在Eclipse 中,启动Tomcat 时,出现: 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting proper ...
- 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to
警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 警告: [SetPro ...
- 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} 解决方法
Tomcat启动时出现红色警告内容 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'sour ...
随机推荐
- (PMP)解题技巧和典型题目分析(模拟二)
- apache学习笔记
httpd -k restart -n apache24 [注意在wamp下名字叫wampapache] http://blog.sina.com.cn/s/blog_692a024c0102vuq ...
- For语句的衍生对象
for in语句: for...in 语句用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作). for...in 语句用于对数组或者对象的属性进行循环操作. for ... in 循环中的 ...
- C++: cin
cin字符的时候, 会忽略掉'\n', ' '等空白符
- MapGIS DataStore
http://www.mapgis.com/index.php/index-show-tid-206.html 异构数据同时加载 DCServer感觉已经集成到 IGServer中了. >> ...
- 基于UML网络教学管理平台模型的搭建
一.基本信息 标题:基于UML网络教学管理平台模型的搭建 时间:2013 出版源:网络安全技术与应用 领域分类:UML:网络教学管理平台:模型 二.研究背景 问题定义:网络教学管理平台模型的搭建 难点 ...
- 【Spring】SpringMVC配置文件
SpringMVC中一般会引入三个配置文件applicationContext.xml.dispatcher-servlet.xml(SpringMVC-servlet.xml).web.xml 1. ...
- 团队-Forward团队-团队一阶段互评
团队名称:Forward团队 学号:2015035107105 得分:7 原因:知识欠缺,能够一边学一边做 学号:2015035107109 得分:6 原因:对我有很多帮助 学号:2015035107 ...
- Appium日志乱码终结指北
缘起 最近Android,IOS自动化多开群控都搞好了,但是Appium中的log 显示中文乱码问题像个苍蝇一样,看着感觉特别难受,挥之不去,抚之不平.论坛搜索了一下,很多帖子都反映过这个问题,但是都 ...
- 《python语言程序设计》_第三章(数字函数、字符串和对象)
3.2_常见的Python函数 (1) abs()函数 求绝对值 (2) max(x1,x2,x3,....)求最大值 (3) min(x1,x2,x3,....)求最小值 (4) pow 返回a的b ...