Tomcat 第二篇:启动流程
1 Tomcat 基本知识
首先介绍一些 Tomcat 的基本知识,防止有纯小白看的云里雾里的。
下面这张图是一个下载好二进制版的的 Tomcat ,直接解压得到的,虽然版本是 9.x ,但是这个目录结构和 8.5 是一致的,不影响介绍。
- bin : 主要用来存放一些脚本文件,一种格式是 sh 的是在 Linux 使用的脚本,另一种格式是 bat 的是在 Windows 中使用的脚本。
- conf : 主要用来存放一些 Tomcat 的配置文件,有 xml 格式的也有 properties 格式的。
- lib : 用来存放一些 Tomcat 运行时所需要的 jar 包。
- logs : 日志目录。
- temp : 存放一些运行过程中产生的临时文件。
- webapps : 这个应该很熟悉,主要用来存放应用程序,可以是 war 包或者是 jar 包。
- work : 主要用来存放 Tomcat 在运行时的编译后文件。清空work目录,然后重启 Tomcat ,可以达到清除缓存的作用。
现在的 IDE(Integrated Development Environment)
工具可以直接将 Tomcat 配置在工具中,比如最常用的 Eclipse 和 IDEA ,启动 Tomcat 的时候只需要点一下按钮就可以启动,实际上这两个 IDE 工具只是帮我们调用了 Tomcat 的启动脚本。
Tomcat 的各种脚本都放在 bin 这个目录下,我们打开看一下:
可以轻易的找到两个启动脚本 startup.bat
和 startup.sh
。一个是 Windows 下的脚本,一个 Linux 下的。
同样,还可以看到两个停止脚本 shutdown.bat
和 shutdown.sh
。
这是在 Tomcat 的二进制包中,我们还可以看下源码包下是什么样的。
可以看到,基本上该有的都有,最重要的启停脚本都还在。
既然我现在是在 Windows 环境下,那么启动就从 startup.bat
看起。
2 Tomcat 启动第一步:startup.bat
第一个打开 startup.bat
这个启动脚本,看下里面写了啥具体,这段脚本不长,我把里面的内容摘出来:
setlocal
rem Guess CATALINA_HOME if not defined
set "CURRENT_DIR=%cd%"
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome
set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"
rem Check that target executable exists
if exist "%EXECUTABLE%" goto okExec
echo Cannot find "%EXECUTABLE%"
echo This file is needed to run this program
goto end
:okExec
rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
call "%EXECUTABLE%" start %CMD_LINE_ARGS%
:end
最开始一大段的 rem 注释我没摘,只摘了最后一部分会执行的内容。
第一段是在设置当前的 CATALINA_HOME
的环境变量,如果没有设置的话,会将当前运行脚本的目录作为该环境变量的值,然后跳转到 :okHome
那里。
接下来设置了 EXECUTABLE
的路径是 %CATALINA_HOME%\bin\catalina.bat
。
然后开始验证验证设置的 EXECUTABLE
中的 catalina.bat
这个文件存不存在,如果不存在的话直接结束,如果存在的话接着往下走。
接下来是将运行脚本前设置的其他参数保存到 CMD_LINE_ARGS
这个变量中,然后在最后执行了 catalina.bat
这个文件,跟了两个参数,第一个是 start
,第二个就是刚才保存的变量 CMD_LINE_ARGS
。
这种脚本代码建议放在编辑器里看,千万不要使用那个 Windows 自带的记事本,用那玩意看估计大多数人直接就看懵了。
我通常是放在 VSCode 中看,会自动对代码进行高亮展示,给大家看下上面这段脚本放在 VSCode 中的样子:
可以看到,正常注释变灰,关键字变蓝高亮,并且跳转语句直接变橙色,非常方便我们阅读。
3 Tomcat 启动第二步:catalina.bat
这个脚本太长了,我就单纯的截取比较重要的进行介绍。
set "CURRENT_DIR=%cd%"
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome
在最开头的地方,校验 CATALINA_HOME
是否存在,如果不存在,则设置 CATALINA_HOME
为当前路径。
接着下面设置了一下 CATALINA_BASE
这个变量。
if not "%CATALINA_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase
接下来到了一个重点内容,判断 setclasspath.bat
是否存在,如果存在的话就执行一下:
rem Get standard Java environment variables
if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath
echo Cannot find "%CATALINA_HOME%\bin\setclasspath.bat"
echo This file is needed to run this program
goto end
:okSetclasspath
call "%CATALINA_HOME%\bin\setclasspath.bat" %1
if errorlevel 1 goto end
这个文件实际上是校验是否设置了 JAVA_HOME
或者 JRE_HOME
的环境变量,如果没有设置则会在控制台打印对应的信息。
接下来是有关于 CLASSPATH
的设置和校验,然后是一堆变量的设置和校验,无需关注,接着使用 echo
打印了一些信息:
echo Using CATALINA_BASE: "%CATALINA_BASE%"
echo Using CATALINA_HOME: "%CATALINA_HOME%"
echo Using CATALINA_TMPDIR: "%CATALINA_TMPDIR%"
if ""%1"" == ""debug"" goto use_jdk
echo Using JRE_HOME: "%JRE_HOME%"
goto java_dir_displayed
:use_jdk
echo Using JAVA_HOME: "%JAVA_HOME%"
:java_dir_displayed
echo Using CLASSPATH: "%CLASSPATH%"
各种比较重要的变量在这里进行了一些打印,接下来又设置了一些比较重要的变量:
set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBUG_OPTS=
set JPDA=
这里的 _EXECJAVA
实际上是我们在 JAVA_HOME
或者是 JRE_HOME
中 bin 下面的 java.exe
。
这里出现的 _RUNJAVA
变量,是在上面的 setclasspath.bat
那个脚本中进行设置的。
而这个 MAINCLASS
的值是 org.apache.catalina.startup.Bootstrap
,这个是我们第一篇文章启动 Tomcat 时候的那个类,不知道各位还有印象不。
接下来设置了一个变量 ACTION
的动作时 start
,用屁股想想应该是启动的意思。
然后对参数进行了一次判断:
if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop
if ""%1"" == ""configtest"" goto doConfigTest
if ""%1"" == ""version"" goto doVersion
如果没有其他参数做覆盖,这里的参数就是上面设置的 start
,直接跳转到最后的 doStart
去了,不过可以看到, Tomcat 启动可以接受的参数有 debug
, run
, start
, stop
, configtest
和 version
,我们平时在 IDE 工具里用的比较多的应该有 debug
, run
, start
, stop
, 剩下的两个至少我是基本上没有使用过,如果不是今天看到这里了,我都不知道 Tomcat 还能有 configtest
和 version
这两个参数。
:doDebug
shift
set _EXECJAVA=%_RUNJDB%
set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\java"
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd
:doRun
shift
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd
:doStart
shift
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd
上面这一段就是我们最常用的三种启动方式,从脚本上来看, debug
比 run
单纯的多设置了两个变量 _EXECJAVA
和 DEBUG_OPTS
,而 start
则是多了一个 TITLE
的判断。
接着往下看,基本上就已经到了这个脚本的最底部,这里执行了一句话,也是核心的一句话:
%_EXECJAVA% %CATALINA_LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -D%ENDORSED_PROP%="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
_EXECJAVA
是我们刚才说的那个 java.exe
,然后是各种运行时参数和系统属性,最后面的 MAINCLASS
,也就是 org.apache.catalina.startup.Bootstrap
,接着是 CMD_LINE_ARGS
,这也是一个命令参数,就是 main
方法上的那个 args
参数,最后一个参数是 ACTION
也就是 start
。
最后归根结底就是一句话,执行 Bootstrap
里面的 main
方法,别看这些个脚本写了一大堆,主要工作就是在校验环境配置以及一些基础系统设置和一些运行时参数的设置。
4 小结
脚本整体来讲不难,而且每段脚本上面都已经有了简单的英文注释,简明扼要的写清楚了这一段脚本在做什么,稍微了解一些基础的 DOS 命令,都可以进行阅读。
至于其他的脚本可以大致浏览下,基本上兜兜转转最后还是会回到 catalina.bat
这个脚本,而在这个脚本中,最后肯定会执行 Bootstrap
里面的 main
方法。
在 Windows 系统中,使用的是 bat 脚本,在 Linux 系统中,就会使用 sh 脚本,这个本质上没有什么大的差别,整体原理都是一样的,有兴趣的同学可以自己研究下 sh 脚本,就当学 shell 语法了。