Tomcat源码分析

浅谈Tomcat架构 中我们大致介绍了Tomcat的核心架构,这里我们再通过Tomcat的源码,结合Tomcat的架构的各个部分及其作用来进行分析。


另外我们在 Tomcat源码环境部署 中也成功部署并运行了Tomcat的源码,这里我们直接以 Bootstrap 启动类来进行查看其主要的流程。


首次其会有一个init的方法,就是去初始化一些类加载器
Tomcat源码分析

在init方法中,它把Catalina这个类利用反射实例化之后,放在了catalinaDaemo之中
Tomcat源码分析

然后我们跳出init方法,继续向下看,Tomcat就会利用load方法去加载配置文件
Tomcat源码分析
Tomcat源码分析

进入load方法之中,这里又会利用反射机制去调用Catalina类的load方法,之前我们在查看Tomcat启动类的时候,在启动文件 startup.bat 中就已经发现会通过Catalina类进行启动的
Tomcat源码分析

在Catalina类的load方法中,最前面和最后面就会统计我们的Tomcat启动时间,我们一般启动项目时,看到的Tomcat启动时间就是通过这打印出来的。
Tomcat源码分析
Tomcat源码分析

然后我们继续看Catalina类load方法之中的内容,它会通过Digester这个类去解析我们的配置文件
Tomcat源码分析

我们看看其解析的是哪一个文件,查看其configFile文件,发现就是我们Tomcat中核心的 server.xml ,我们之前也发现该文件中和Tomcat架构是一致的
Tomcat源码分析
Tomcat源码分析

读取到了 server.xml 文件后,我们判断其为不为空之类的,我们继续向下看
Tomcat源码分析

我们会发现有个server-embed.xml文件的处理,这里主要是针对内嵌的tomcat进行处理
Tomcat源码分析

继续向下看,然后就会对我们的 server 文件进行解析,这里就不细看了,其实就是解析我们的xml文件,在MyBatis中也是有类似的解析之类的,继续向下看
Tomcat源码分析

在下面,这里就真正的开始来创建我们Tomcat架构中的最外层的Server层了,我们查看其init方法
Tomcat源码分析

这里我们发现了调用了是其Lifecycle接口的方法,我们看其实现类
Tomcat源码分析

这里Lifecycle接口就有一个默认的实现类LifecycleBase类,我们继续查看其initInternal方法
Tomcat源码分析

我们发现该方法是一个抽象方法,它有很多的实现类,这里为什么要这样设计呢?Tomcat源码分析

我们在浅谈Tomcat架构 中提到了我们Tomcat中很多的类都是继承了Liftcycle接口,它好处是生命周期统一接口Lifecycle把所有的启动、 停止、 关闭等都放在一起统一管理,这里就是利用了 模板模式 来实现这一点的,下面还会体现这一点的。


我们发现我们要创建的Server是实现了Lifecycly的接口的,这里我们直接查看其标准的实现类
Tomcat源码分析

我通过上述的模板模式可以肯定的是,Server的实现了StandardServer肯定是要实现initInternal方法的,不然它怎么进行创建Server层呢,它通过Lifecycle绕了一下就会为了统一管理生命周期而已。


然后我们在Server实现类StandardServer中就会发现这里又会用同样的方式去创建我们的Service,并且我们知道一个Server是可以有多个Service的,所以这里使用for循环去创建多个Service
Tomcat源码分析

上图中的init方法,和我们在创建Server的时候一致,也是通过Lifecycle接口的init方法,这里我们就不重复看了,这里查看其Service
Tomcat源码分析

也是实现了该接口,我们直接查看其实现类StandardService的initInternal方法,如下,我们之前在server.xml配置文件中提到过,我们还可以在其中配置线程池来使用,如果配置类这里就会进行初始化
Tomcat源码分析

接下来,就是进行创建我们的Connector类,是用于接受请求并将请求封装成Request和Response,然后交给Container进行处理
Tomcat源码分析

这里又是init方法,它也是和之前同样的作用,我们直接查看Connector类的initInternal方法
Tomcat源码分析

这里我们就会发现一个熟悉ProtocolHandler了,这里我们之前就曾经说过的,如下
Tomcat源码分析

这里我们就查看下ProtocolHandler的init方法,发现其是个接口方法,继续查看其实现类 AbstractProtocol
Tomcat源码分析

在实现类AbstractProtocol中,我们又发现了endpoint,这个我们从上图也可以得知其作用的,继续查看
Tomcat源码分析

我们从init方法体内又会发现一个bind的抽象方法
Tomcat源码分析

这个实现类的作用是什么呢?就是决定了Tomcat是使用传统的BIO还是NIO的形式,如果打开的源码是8.0.xx之前的版本,就会从中看到有关BIO的实现类。




到此我们一个Tomcat的load就完成了,其load方法下的start方法和load方法都是类似的,也是采用相同的方式来处理其生命周期等问题,我们从Server到Service到Connector,我们就可以去监听外部的请求了,这里我们主要在看看当Connector接口到了请求后,转发给Container处理,Container如何处理请求的。


Container处理请求是使用Pipeline-Valve管道来处理的,Pipeline-Valve是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后将处理后的请求返回,再让下一个处理着继续处理。
Tomcat源码分析

这里我们结合上图,可以去我们Tomcat的源码中进行查看,如第一个Engine
Tomcat源码分析
Tomcat源码分析
Tomcat源码分析

对于其他的Host、Context、Wrapper都是类似的,如下
Tomcat源码分析
Tomcat源码分析
Tomcat源码分析

这其中StandardEngine、StandardHost、StandardContext、StandardWrapper类全部都是继承了ContainerBase类的,所以我们pipeline其实都是同一个管道
Tomcat源码分析

这里我们就可以看到Container包含的四个子容器中分别对应的StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve,这四个ValveBase(因为继承ValveBase抽象类)是不可删除的(因为直接在其类的构造方法之中嘛),它们主要是在上层容器的管道中调用下层容器的管道。


  1. Connector在接收到请求后会首先调用最顶层容器的Pipeline来处理,这里的最顶层容器的Pipeline就是EnginePipeline(Engine的管道)

  2. 在Engine的管道中依次会执行EngineValve1、EngineValve2等等,最后会执行StandardEngineValve,在StandardEngineValve中会调用Host管道,然后再依次执行Host的HostValve1、HostValve2等,最后在执行StandardHostValve,然后再依次调用Context的管道和Wrapper的管道,最后执行到StandardWrapperValve

  3. 当执行到StandardWrapperValve的时候,会在StandardWrapperValve中创建FilterChain,并调用其doFilter方法来处理请求,这个FilterChain包含着我们配置的与请求相匹配的Filter和Servlet,其doFilter方法会依次调用所有的Filter的doFilter方法和Servlet的service方法,这样请求就得到了处理

  4. 当所有的Pipeline-Valve都执行完之后,并且处理完了具体的请求,这个时候就可以将返回的结果交给Connector了,Connector在通过Socket的方式将结果返回给客户端