上一篇:Tomcat8源码分析-类结构图html
前面已经将Tomcat的类结构和架构介绍了一下,如今经过DEBUG代码看看代码是如何一层层调用的,下图为启动过程当中的准备+load详细过程java
从整个图中能够观察到出现频次最高的就是init\initInternal\fireLifecycleEvent,在类图中也特地罗列了出来,说明主体流程就是靠这些方法来完成的。这三个方法的调用就是一个模板,即:init(LifecycleBase)->setStateInternal(LifecycleBase)->initInternal(StandardXxx)->setStateInternal(LifecycleBase),能够说几乎全部关键的实现都是在initInternal和LifecycleListener中完成的。web
启动从一个BootStrap类开始,先执行它的静态块(完成了Tomcat工做目录初始化),BootStrap.main方法接着就调用BootStrap.init方法(肯定三个ClassLoader,Catalina类实例化),再而后就经过反射调用Catalina.load方法,开始了加载过程。apache
再还没看源码以前,猜测一下Tomcat启动过程当中是否是应该有以下这些动做:设计模式
1.获取server.xml缓存
2.解析server.xml网络
3.处理Tomcat本身内部默认的一些配置或者约束或者规则什么的多线程
4.根据解析的结构生成Tomcat架构对应的实例结构 架构
5.既然要接收请求,须要绑定与监听端口app
6.找到目录下有哪些应用
7.解析每一个应用下的web.xml文件
8.处理Servlet\Servlet-Mappping\Filter
9.等一切都准备就绪,Tomcat如何接收到请求,将请求封装为request,将request传给谁处理,处理以后又如何封装为request,如何发送回客户端
10.经过什么BIO\NIO\NIO2等等IO方式完成网络操做
下面就看看load过程当中有作的事情,包含了以上那些步骤。
虽然知道有一些StandardXxx类,可是稍微想一想也不会是由这些类去完成server.xml的定位和解析,由于它本身自己就须要解析配置完成,那么在类图中能够看到是有Catalina.configFile()这行代码,最终看到了熟悉的"server.xml",看到这里是否是接下来就应该执行解析了喃?往下看。。。
file = configFile(); protected File configFile() { File file = new File(configFile); if (!file.isAbsolute()) { file = new File(Bootstrap.getCatalinaBase(), configFile); } return file; } protected String configFile = "conf/server.xml";
代码继续往下翻以前能够先看看这段代码:
Digester digester = createStartDigester()
Digester(有道词典翻译是蒸煮器,煮解器),我就把它叫作解析器吧,毕竟它后面又用parse()完成对server.xml的解析。刚点进去看的时候,有点被吓着了,都是一大堆不认识的鬼。。。摘了部分代码以下:
digester.addObjectCreate("Server", "org.apache.catalina.core.StandardServer", "className"); digester.addObjectCreate("Server/Service", "org.apache.catalina.core.StandardService", "className"); digester.addObjectCreate("Server/Service/Executor", "org.apache.catalina.core.StandardThreadExecutor", "className"); //这里面还会添加不少规则,好比设置EngineConfig digester.addRuleSet(new EngineRuleSet("Server/Service/")); //这里面还会添加不少规则,好比设置HostConfig(它会负责完成Context组件实例化和应用部署) digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
这样看上去就不会那么恐怖了,见到了熟悉的StandardServer,StandardService,能够猜测在解析的时候,是否是根据server.xml中的标签名字会从这里拿到对应类的全路径反射生成实例喃?看一张动图(3秒一帧)
接着往下,上面准备了规则(配置文件中对应标签应该实例化那些类,默认添加了那些监听器给对应的标签),找到了server.xml文件路径,接下来就要真正的解析和处理了,看代码
try { inputSource.setByteStream(inputStream); digester.push(this); //关键理解点2:将Catalina对象传给解析器,解析器完成以后,Server就已经有值了。如: // Server-Service-Engine-Host已经完成实例化。 // Server-Service-Connector-(HTTP/AJP)ProtocolHandler-EndPoint //将断点放到这里看先后server的层级,能够匹配上Tomcat架构图 digester.parse(inputSource); } catch (SAXParseException spe) { ...省略.... } catch (Exception e) { ...省略.... } } finally { ...省略.... }
这部分代码执行完,Server就已经实例化完了,但不是全部的内部属性都构造好了,还有很长的路要走好比init/start。
既然Server已经有了,再仔细看看它的内部结构,上动图
能够看到Server-Service-Engine-Host,Server-Service-Connector这两条线都已经有了,可能会问怎么还没看到Context-Wrapper喃,由于那是在start阶段完成的。
parse()方法里面的具体逻辑就不须要去剖析了,只须要知道它完成了Server-Service-Engine-Host等等的实例化,并添加了监听和Valve规则(这里看不懂不要紧,等后面就会知道了)。
到此为止,Server的内部结构雏形已经出来了,再看看往下的server.init-engint.init等等xxx.init是如何一层层调用的
代码往下走,看到了service.init
// Start the new server try { //Server Init操做,在这里会一层层的往下Init。Server-Service-Engine/Connector-Host getServer().init(); } catch (LifecycleException e) { if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) { throw new java.lang.Error(e); } else { log.error("Catalina.start", e); } }
从这里开始就是模板方法设计模式开始发功的时候了,若是还不知道的话,赶忙点进去看看,并动手写写。有经验的话能够想起在JDK的不少源码都能看到这种设计模式,好比多线程中的同步器,还有Spring提供的BeanDefinitionRegistryPostProcessor扩展点等。
在看动图以前下描述一下:凡是LifecycleBase的子类,调用的init方法必定是LifecycleBase.init(由于该方法被声名为final了),里面就是setStateInternal-fireLifecycleEvent-initInternal-setStateInternal-fireLifecycleEvent这样的套路。看到这一点很重要,不然往下DEBUG脑袋会发蒙的。
下面这张动图描述了Server-Service-Engine-Host这条线,至于Server-Service-Engine-Connector这条线是一样的方式。
总结:
1、Catalina在调用StandardServer.init以前完成了对server.xml解析,生成的Server对象的内部层次结构,初始化了默认的一些参数对应的实例
2、StandardServer.init执行以后完成了以下几件事情:
1.Server-Service-Engine-Connector的状态都变成了INITIALIZED
2.Connector中HTTP/AJP协议对应的ProtocolHandler也都实例化完成,监听启动完成
如图:
但此时是没法访问Tom猫的主页的,由于还没start,也就是尚未部署应用。假设你尝试使用http://localhost:8080去访问,会一直没有响应。
3.MapperListener初始化完成
MapperListener经过监听容器事件来完成对容器的注册和取消注册。而Mapper用于对容器进行缓存和管理,同时提供uri映射的功能
在这里推荐两个博客:
爱吃鱼的KK(里面有不少深刻的分析)