环境准备
- IntelliJ IDEA 2024.1.4 (需要安装Ant插件)
- JDK 1.8
- Ant 1.10.13
源码仓库: https://github.com/apache/tomcat | 源码Tag: 8.5.38
前言
Tomcat是Apache基金会开源的Servlet型Web服务器, 在Spring Boot系列框架中作为默认Web服务器组件。
Tomcat是一个历史悠久的Web服务组件, 它的项目管理工具使用的是Ant, 而不是Maven; 它所支持的JDK版本比较低, 在本Tag中可观察到为JDK1.7。
解决编译问题
打开Ant插件, 可以看到几十个Task可以执行。
打开build.xml文件, 首先要注意的应该是build.properties的文件名,刚好项目目录内有个build.properties.default的文件, 复制一份改个build.properties的名试下叭。
在这个文件中, 我们需要修改base.path, 这项配置是tomcat编译时依赖的Jar包的存放位置。默认配置如下:
1 | base.path=${user.home}/tomcat-build-libs # 即 ~/tomcat-build-libs |
然后找到Ant插件内显示的两个Task, deploy和embed, 分别是用来构建Tomcat独立服务和嵌入式Jar包(就是spring-boot-starter-tomcat用的依赖)。
执行完成后, 会出现output目录。
寻找程序入口
阅读源码, 一种方式是首先找到我们最常用的启动方式, 并找到程序入口。
首先, 我们先将Tomcat作为独立服务来看待,在output/build/bin
中找到startup.sh
, 可以看到最后一行如下:
1 | exec "$PRGDIR"/"$EXECUTABLE" start "$@" |
那么我们搜索 EXECUTABLE
可以看到就是调用了catalina.sh
打开以后翻到底部, 发现好长的一连串 if-else, 实际上这些都不重要, 只是在做一些启动参数解析及预处理。我们知道启动Java程序肯定会有启动类的路径, 所以直接搜索org.apache
, 肯定能发现很多都试用了下面这个Class:
1 | org.apache.catalina.startup.Bootstrap |
找到这个文件, 在里面果然发现了main方法, 所以程序入口就找到了。
实际上, 笔者并不是直接搜索的包路径, 而是粗略的看了一下那些if-else, 从下往上看,发现大部分是
exit 1
, 而剩下的就是正常启动命令咯, 然后就顺理成章的发现了Bootstrap, 找到了main方法。
探究如何启动
查看Bootstrap类的main方法, 主要就是三行代码
bootstrap.init()
: 初始化, 这里主要就是处理 ClassLoaderdaemon.load(args)
: 这里args是我们执行命令行中传递的参数daemon.start()
: 这就是正式启动的方法
这里daemon 和 bootstrap 其实是一个对象, 只是调用时机不同, 引用的名称不同
分析一下, 这三个方法依次点击进去看一下, 实际上看似在操作bootstrap
, 实则是在操作Catalina
, 我们把代码跟下来, 会发现init() 是在设置 catalinaDaemon
这个属性, 而load和start都是在使用反射执行Catalina
的对应方法
Catalina的Server属性, 即为Web服务器的核心业务, 而start方法也最终也会执行到getServer().start()方法
另一种启动方式
如果你看过springboot的Servlet类型Web服务启动代码, 会发现它是使用Tomcat这个类的start()方法启动的, 没有任何Catalina相关的代码. 那我们再来看下Tomcat和Calalina有什么区别呢?
在Tomcat中也存在start方法, 只是不再需要Bootstrap.init和 load()方法了,而是直接使用Tomcat.init方法进行初始化. 也就是直接通过代码调用的方式启动, 不需要使用命令行方式进行启动和终止了.
总结
由此可见, Calalina就是命令行方式的核心启动类; 而Tomcat就是嵌入式的核心启动类.
__END__