这是我们深入理解tomcat的第五篇文章,按照我们的思路,这次我们本应该区分析tomcat的连接器组件,但楼主思前想后,觉得连接器组件不能只是纸上谈兵,需要深入源码,但楼主本能的认为我们应该先分析tomcat的启动过程,以能够和我们上一篇文章深入理解 Tomcat(四)Tomcat 类加载器之为何违背双亲委派模型
相衔接。因为启动类加载器的核心代码就在启动过程中,所以,我决定先分析tomcat的启动过程,结合源码了解tomcat的类加载器如何实现,以彻底了解tomcat的类加载器。
因为Tomcat 的启动过程非常复杂,因此楼主将启动过程拆开分析,不能像之前说的按照启动过程分析了,否则,文章篇幅过长,条理也会变得不清晰,Tomcat的启动过程包括了初始化容器的生命周期,还涉及到JMX的管理,还有我们现在分析的类加载器,因此,我们必须换个维度分析。
再一个,因为连接器和容器紧紧关联,连接器的作用就是分析http请求,所以,楼主觉得我们之前的计划可能需要变更一下,我们将在分析完生命周期和类加载器之后将结合源码分析连接器和容器,以了解tomcat的核心组件在接受HTTP请求后如何运行。
所以,今天,我们的任务就是debug tomcat 源码,分析tomcat启动过程的每一步操作。在看这篇文章之前希望同学们看看我们的第四篇分析tomcat的文章以了解tomcat的类加载器。
下面是这篇文章的目录结构:
1. 启动tomcat,进入main方法
2. 进入 init 方法
3. 进入 setCatalinaHome 方法
4. 进入 setCatalinaBase 方法
5. 接下来则是类加载器大显身手的时候了. 进入 intiClassLoaders 方法
6. 进入 createClassLoader 方法
7. 我们回到 initClassLoaders 方法中来
8. 再回到 init 方法中, 类加载器初始化结束, 接下来干嘛?
9. 设置完线程上下文类加载器之后做什么呢? 进入 securityClassLoad 方法
10. 进入 loadCorePackage 方法
11. 回到 init 方法
12. 寻找 WebAppClassLoader, 进入 startInternal 方法
13. 进入 createClassLoader 方法
14. tomcat 类加载结构体系创建完毕
1. 启动tomcat,进入main方法
我们打开我们之前clone下的Tomcat-Source-Code 源码,找到Bootstrap 类,找到main方法,在451行打上断点,启动main方法,开始我们的调试:
可以看到楼主已经写了很多的注释,因为楼主已经debug过了.
我们看代码,首先判断”守护“对象是否为null,肯定为null了,然后进入if 块, 创建一个默认构造器的Bootstrap对象,有一行注释// Don't set daemon until init() has completed
, 说不要在init方法完成之前设置daemon 变量,因为后面的很多步骤都依赖该变量,所以必须初始化结束后才能设置值,再继续看,进入init方法:
2. 进入 init 方法
该方法注释:Initialize daemon.
表明要初始化该守护程序,也就是这个变量Bootstrap:
我们看看该方法,首先setCatalinaHome()
方法,也就是我们启动虚拟机的时候设置的 VM 参数:
我们进入该方法看看
3. 进入 setCatalinaHome 方法
很明显,我们设置过 Catalina.home , 所以获取classpath下的catalina.home 的值不为null,所以直接return, 如果不为null,则从项目根目录下获取boostrap的jar包。如果存在,则设置上一级目录为 catalina.home, 如果不存在,则设置项目根目录为 catalina.home.这就是 setCatalinaHome 方法的逻辑.
4. 进入 setCatalinaBase 方法
下一步是执行 setCatalinaBase 方法, 也是一样能获取catalina.base
, 直接 return,如果不存在, 则设置catalina.home
为catalina.base
, 如果catalina.home
也是空,那么则设置项目根目录为catatlina.base
.