前言
我们都知道只需要在Tomcat中bin
目录下启动startup.bat/sh
,那么整个Tomcat就可以启动起来给我们提供服务,我们不免心生疑问启动startup.bat/sh
以后,Tomcat到底是如何启动的,那么下面我们就来一步一步分析吧!
启动第一步(startup.bat
)
既然启动tomcat需要启动startup.bat/sh
,那么我们就从startup.bat/sh
开始看起吧。笔者因操作系统使用的win系统,所以就只看了startup.bat
,实际上startup.sh
是给linux系统准备的启动程序并且两者所做的事情完全相同,只是为不同的系统准备的而已,所以只需要查看一个即可。
.bat
文件是Windows中双击的可执行文件。为了大家能够读懂上面的程序,需要先学习一些批处理文件的基本命令。
rem: 该命令用于注释,rem起始的行不会作为代码执行
pause: 该命令用于暂停正在执行的批处理文件,并且提示用户按键,然后程序继续执行
echo: 该命令用于在dos控制台显示一段文本,相当于print,如果想要显示环境变量需要在环境变量前后加上%,例如显示操作系统 echo %OS%
echo off: 该命令可以防止将批处理文件中的具体命令打印出来,而只会输出执行结果。
@echo off:该命令与echo off相同,唯一的区别在于 @echo off不仅会隐藏具体命令还会连'echo off'这个自身命令也隐藏起来。
set: 设置环境变量,例如 set A = 100 设置A变量为100
label: 使用 ':'(冒号)来设置一个标签,供给goto命令使用,例如":init"代表一个init标签。
goto: 该命令使正在执行的命令强制跳转到他指定的标签。例如我需要跳转指定A标签下的命令,如下:goto A
not: 该命令用来取反,相当于逻辑非。
if: 该命令表示判断
exist: 该命令通常用来测试文件是否存在,一般和if一起使用
shift: 该命令用来将参数后移一位即将%2%赋值给%1%,%3%赋值给%2%,也可以理解为参数列表左移即删除现有参数列表的第一位。
call: 该命令用来调用另外一条命令。
setLocal: 该命令表示该批处理文件中修改的环境变量只在本文件中起作用,或者直到endLocal命令出现,被修改的环境变量才恢复原状。
start: 重新开启一个dos窗口。
使用编辑器打开bin/startup.bat
我们可以看到如下的代码:
@echo off
rem 第一部分
rem Licensed to the Apache Software Foundation (ASF) under one or more
rem contributor license agreements. See the NOTICE file distributed with
rem this work for additional information regarding copyright ownership.
rem The ASF licenses this file to You under the Apache License, Version 2.0
rem (the "License"); you may not use this file except in compliance with
rem the License. You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.
rem ---------------------------------------------------------------------------
rem Start script for the CATALINA Server
rem ---------------------------------------------------------------------------
setlocal
rem 第二部分
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%incatalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
rem 第三部分
:gotHome
if exist "%CATALINA_HOME%incatalina.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
rem 第四部分
:okHome
set "EXECUTABLE=%CATALINA_HOME%incatalina.bat"
rem 第五部分
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
rem 第六部分
: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%
rem 第七部分
:end
分析
在标注第一部分
的地方全是注释,对软件的License做了说明。
正式代码开始在标注第二部分
的地方开始。
- 设置变量
CURRENT_DIR
为当前目录,例如你打开了tomcat
的bin
目录,那么CURRENT_DIR
就指向了bin
目录。 - 判断系统变量
CATALINA_HOME
如果不是空串,那么就跳转到gotHome
标签执行,实际上我们很少去设置CATALINA_HOME
这个系统变量,所以我们继续往下看。 - 设置
CATALINA_HOME
为CURRENT_DIR
指向的目录,也就是bin
目录。 - 判断
CATALINA_HOMEincatalina.bat
文件是否存在,如果存在就转向okHome
标签,明显CATALINA_HOME
现在指向的是bin
目录,那么binincatalina.bat
文件是不存在的,所以继续往下看,不会跳转到okHome
。 cd..
退出到上一级目录- 设置
CATALINA_HOME
指向当前目录,也就是Tomcat
的根目录。 - 进入
CURRENT_DIR
指向的目录,也就是bin
。
继续看标注第三部分
的地方的代码。
- 执行
gotHome
标签。 - 如果存在
CATALINA_HOME%incatalina.bat
这个文件就跳转执行okHome
标签。
继续看标注第四部分
的地方的代码。
- 设置变量
EXECUTABLE
指向catalina.bat
文件
继续看标注第五部分
的地方的代码。
- 双重保险继续判断下
EXECUTABLE
指向的catalina.bat
文件是否存在。存在就跳转执行okExec
标签。
继续看标注第六部分
的地方的代码。
set CMD_LINE_ARGS=
表示清空变量CMD_LINE_ARGS
。- 执行
setArgs
标签 - 第一个变量(
%1%)
为空字符串,那么就跳转到doneSetArgs
标签,因为我们是直接运行startup.bat
,没有传递任何参数,所以我们应该是跳转到doneSetArgs
标签,由此也可以猜想出,如果不是使用双击执行的话,使用命令行启动startup.bat
那么是可以传递参数的。 - 跳转到
doneSetArgs
,调用EXECUTABLE
指向的文件,也就是catalina.bat
文件,同时传递start
参数,因为CMD_LINE_ARGS
为空,所以只传递了一个start
参数
第七部分
- 可以看出
end
标签是很多,判断失败跳转的标签,是参数不正确的时候的结束标志。
启动第二步(catalina.bat
)
继续上面分析,在所有参数正确的条件下,startup.bat
文件会设置CATALINA_HOME
变量,并且调用catalina.bat
文件,同时传递参数start
,那么我们继续打开catalina.bat
看看,这个文件又做了什么。
catalina.bat
代码如下:
@echo off
rem 第一部分
rem Suppress Terminate batch job on CTRL+C
if not ""%1"" == ""run"" goto mainEntry
if ""%TEMP%"" == """" goto mainEntry
if exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.run"
if not exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.Y"
call "%~f0" %* <"%TEMP%\%~nx0.Y"
rem Use provided errorlevel
set RETVAL=%ERRORLEVEL%
del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1
exit /B %RETVAL%
:mainEntry
del /Q "%TEMP%\%~nx0.run" >NUL 2>&1
rem 第二部分
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%incatalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%incatalina.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
rem Ensure that any user defined CLASSPATH variables are not used on startup,
rem but allow them to be specified in setenv.bat, in rare case when it is needed.
rem 第三部分
set CLASSPATH=
rem Get standard environment variables
if "%CATALINA_BASE%" == "" goto gotSetenvHome
if exist "%CATALINA_BASE%insetenv.bat" call "%CATALINA_BASE%insetenv.bat"
goto gotSetenvBase
:gotSetenvHome
if exist "%CATALINA_HOME%insetenv.bat" call "%CATALINA_HOME%insetenv.bat"
:gotSetenvBase
rem 第四部分
rem Get standard Java environment variables
if exist "%CATALINA_HOME%insetclasspath.bat" goto okSetclasspath
echo Cannot find "%CATALINA_HOME%insetclasspath.bat"
echo This file is needed to run this program
goto end
:okSetclasspath
set "BASEDIR=%CATALINA_HOME%"
call "%CATALINA_HOME%insetclasspath.bat" %1
if errorlevel 1 goto end
rem 第五部分
rem Add on extra jar file to CLASSPATH
rem Note that there are no quotes as we do not want to introduce random
rem quotes into the CLASSPATH
if "%CLASSPATH%" == "" goto emptyClasspath
set "CLASSPATH=%CLASSPATH%;"
:emptyClasspath
set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%inootstrap.jar"
if not "%CATALINA_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase
if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set "CATALINA_TMPDIR=%CATALINA_BASE% emp"
:gotTmpdir
rem 第六部分
rem Add tomcat-juli.jar to classpath
rem tomcat-juli.jar can be over-ridden per instance
if not exist "%CATALINA_BASE%in omcat-juli.jar" goto juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%in omcat-juli.jar"
goto juliClasspathDone
:juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_HOME%in omcat-juli.jar"
:juliClasspathDone
if not "%LOGGING_CONFIG%" == "" goto noJuliConfig
set LOGGING_CONFIG=-Dnop
if not exist "%CATALINA_BASE%conflogging.properties" goto noJuliConfig
set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%conflogging.properties"
:noJuliConfig
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%
if not "%LOGGING_MANAGER%" == "" goto noJuliManager
set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
:noJuliManager
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%
rem 第七部分
rem ----- Execute The Requested Command ---------------------------------------
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=
if not ""%1"" == ""jpda"" goto noJpda
set JPDA=jpda
if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport
set JPDA_TRANSPORT=dt_socket
:gotJpdaTransport
if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress
set JPDA_ADDRESS=8000
:gotJpdaAddress
if not "%JPDA_SUSPEND%" == "" goto gotJpdaSuspend
set JPDA_SUSPEND=n
:gotJpdaSuspend
if not "%JPDA_OPTS%" == "" goto gotJpdaOpts
set JPDA_OPTS=-agentlib:jdwp=transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND%
:gotJpdaOpts
shift
:noJpda
rem 第八部分
if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop
if ""%1"" == ""version"" goto doVersion
echo Usage: catalina ( commands ... )
echo commands:
echo debug Start Catalina in a debugger
echo debug -security Debug Catalina with a security manager
echo jpda start Start Catalina under JPDA debugger
echo run Start Catalina in the current window
echo run -security Start in the current window with security manager
echo start Start Catalina in a separate window
echo start -security Start in a separate window with security manager
echo stop Stop Catalina
echo version What version of tomcat are you running?
goto end
: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%confcatalina.policy"
goto execCmd
:doRun
shift
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%confcatalina.policy"
goto execCmd
:doStart
shift
if not "%OS%" == "Windows_NT" goto noTitle
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
goto gotTitle
:noTitle
set _EXECJAVA=start %_RUNJAVA%
:gotTitle
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%confcatalina.policy"
goto execCmd
:doStop
shift
set ACTION=stop
set CATALINA_OPTS=
goto execCmd
:doVersion
%_EXECJAVA% -classpath "%CATALINA_HOME%libcatalina.jar" org.apache.catalina.util.ServerInfo
goto end
rem 第九部分
:execCmd
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
rem Execute Java with the applicable properties
if not "%JPDA%" == "" goto doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurity
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:end
一眼看上去代码真的很多,也很乱,也有很多看不懂的东西,好吧,我们慢慢来分析,一步一步来。
第一部分
rem Suppress Terminate batch job on CTRL+C
if not ""%1"" == ""run"" goto mainEntry
if ""%TEMP%"" == """" goto mainEntry
if exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.run"
if not exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.Y"
call "%~f0" %* <"%TEMP%\%~nx0.Y"
rem Use provided errorlevel
set RETVAL=%ERRORLEVEL%
del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1
exit /B %RETVAL%
:mainEntry
del /Q "%TEMP%\%~nx0.run" >NUL 2>&1
-
if not ""%1"" == ""run"" goto mainEntry
:第一个参数不是run
,就转向mainEntry
标签,我们传递的第一个参数从上面来看是start
,所以直接看mainEntry
标签。 -
del /Q "%TEMP%\%~nx0.run" >NUL 2>&1
,第一眼看上去什么鬼,不要方,乍一看好像是个删除的命令,但是后面的%~nx0.run >NUL 2>&1
完全看不懂。遇到这种情况第一步可以先做个测试,我们新建一个test.bat
文件,里面写上如下命令,看看会打印出来什么。我们如果是双击执行的话,需要在下一行加上pause
来停止下窗口便于观看。test.bat
@echo off
echo 'TEMP' = %TEMP%
echo '%~nx0.run' = %~nx0.run
pause
可以看到如下输出
'TEMP' = C:UsersADMINI~1AppDataLocalTemp
'test.bat.run' = est.bat.run
由此可见 TEMP
目录指向了我们环境变量的临时文件目录,%~nx0
则指向了我们本身运行的文件名,不包含全目录,单纯的文件名,那么>NUL 2>&1
这个东西,我们只好查阅相关资料了.
>NUL
表示前面命令执行抛出的异常将不显示/Q 安静模式。删除全局通配符时,不要求确认
1是标准输出
2是错误输出
和 >> 都是输出重定向符号。标准输出默认是打印到控制台,如果要导入到文件,就需要使用>或>>。> 会覆盖已有的文件内容,而>>会附加到已有内容之后。
< 和 << 是输入重定向符号。从文件中读取内容。
2>&1 是把错误输出导入(合并)到标准输出流中
所以mainEntry
这个标签的作用就是,删除临时目录下的catalina.bat.run
文件,如果出错也不提示。第一部分的其他行代码基本大同小异,也可以继续通过echo
命令来测试,第一部分的整体作用其实是针对ctrl+c
命令终止进程所做的操作而已。可以参看上面的注释rem Suppress Terminate batch job on CTRL+C
第二部分
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%incatalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%incatalina.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
- 设置
CURRENT_DIR
为当前目录bin
(假如你是在bin
目录中启动) CATALINA_HOME
不是空就转向okHome
- 设置
CATALINA_HOME
指向CURRENT_DIR
的目录,也就是bin
目录。 - 如果存在
%CATALINA_HOME%incatalina.bat
,那么就转向okHome
,否则退出到父目录,(显然不存在binincatalina.bat
) - 设置
CATALINA_HOME
为当前目录(也就是Tomcat的根目录) - 进入
CURRENT_HOME
指向的目录,也就是bin
目录,执行gotHome
标签 - 如果存在
%CATALINA_HOME%incatalina.bat
,就转向okHome
,现在CATALINA_HOME
指向的目录是Tomcat的安装目录,所以incatalina.bat
文件是存在的,所以转向okHome
标签。 - 如果
CATALINA_BASE
变量不是空,就转向gotBase
标签。(显然为空) - 设置
CATALINA_BASE
的值等同与CATALINA_HOME
的值。(现在CATALINA_BASE
也指向的Tomcat的根目录了)
第三部分
set CLASSPATH=
rem Get standard environment variables
if "%CATALINA_BASE%" == "" goto gotSetenvHome
if exist "%CATALINA_BASE%insetenv.bat" call "%CATALINA_BASE%insetenv.bat"
goto gotSetenvBase
:gotSetenvHome
if exist "%CATALINA_HOME%insetenv.bat" call "%CATALINA_HOME%insetenv.bat"
:gotSetenvBase
- 清空CLASSPATH
- 如果不存在
%CATALINA_BASE%insetenv.bat
文件,那么就转向checkSetenvHome
标签,我们现在使用的是apache-tomcat-7.0.67
,该文件是不存在的,所以转向checkSetenvHome
标签。 checkSetenvHome
标签,如果存在%CATALINA_HOME%insetenv.bat
,那么就调用%CATALINA_HOME%insetenv.bat
文件,显然依旧不存在。- 继续执行
goto gotSetenvBase
,gotSetenvBase
标签为空,继续往下执行。
第四部分
rem Get standard Java environment variables
if exist "%CATALINA_HOME%insetclasspath.bat" goto okSetclasspath
echo Cannot find "%CATALINA_HOME%insetclasspath.bat"
echo This file is needed to run this program
goto end
:okSetclasspath
set "BASEDIR=%CATALINA_HOME%"
call "%CATALINA_HOME%insetclasspath.bat" %1
if errorlevel 1 goto end
- 如果存在
%CATALINA_HOME%insetclasspath.bat
,那么就转向okSetclasspath
标签,(显然存在) - 设置
BASEDIR
指向CATALINA_HOME
- 调用
setclasspath.bat
并且传递第一个参数(start
),有兴趣的同学可以自行查看setclasspath.bat
文件做了什么,其实就是设置了JAVA_HOME
,JRE_HOME
等变量的值。
第五部分
rem Add on extra jar file to CLASSPATH
rem Note that there are no quotes as we do not want to introduce random
rem quotes into the CLASSPATH
if "%CLASSPATH%" == "" goto emptyClasspath
set "CLASSPATH=%CLASSPATH%;"
:emptyClasspath
set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%inootstrap.jar"
if not "%CATALINA_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase
if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set "CATALINA_TMPDIR=%CATALINA_BASE% emp"
:gotTmpdir
- 如果
CLASSPATH
变量为空,就跳转到emptyClasspath
标签,由上面能看出来,CLASSPATH
变量的确是空的,所以跳转到emptyClasspath
标签。 - 设置
CLASSPATH
指向%CLASSPATH%%CATALINA_HOME%BINBOOTSTRAP.JAR
(也就是TOMCAT安装目录下BINBOOTSTRAP.JAR
)。 - 如果
CATALINA_BASE
不为空(这里是为空)那么转向gotBase
标签,gotBase
为空标签,继续往下执行,设置CATALINA_BASE
等于CATALINA_HOME
- 如果
CATALINA_TMPDIR
变量不为空(运行到这里的时候为空)转向gotTmpdir
标签,否则设置CATALINA_TMPDIR
的值为CATALINA_BASE emp
,也就是Tomcat安装目录下的temp
文件夹。gotTmpdir
为空标签。
第六部分
rem Add tomcat-juli.jar to classpath
rem tomcat-juli.jar can be over-ridden per instance
if not exist "%CATALINA_BASE%in omcat-juli.jar" goto juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%in omcat-juli.jar"
goto juliClasspathDone
:juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_HOME%in omcat-juli.jar"
:juliClasspathDone
if not "%LOGGING_CONFIG%" == "" goto noJuliConfig
set LOGGING_CONFIG=-Dnop
if not exist "%CATALINA_BASE%conflogging.properties" goto noJuliConfig
set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%conflogging.properties"
:noJuliConfig
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%
if not "%LOGGING_MANAGER%" == "" goto noJuliManager
set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
:noJuliManager
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%
- 如果不存在
%CATALINA_BASE%in omcat-juli.jar
那么就跳转到juliClasspathHome
标签,我们使用的tomcat版本是存在的,所以继续执行。 - 该命令
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%in omcat-juli.jar"
表示将tomcat-juli.jar
的路径添加到CLASSPATH
中。 - 跳转
juliClasspathDone
标签,juliClasspathDone
是空标签 - 继续执行,如果
LOGGING_CONFIG
变量不为空就跳转到noJuliConfig
标签,否则这只LOGGING_CONFIG=-Dnop
- 如果不存在
%CATALINA_BASE%conflogging.properties
,那么就跳转noJuliConfig
标签,否则设置LOGGING_CONFIG
等于-Djava.util.logging.config.file="%CATALINA_BASE%conflogging.properties"
noJuliConfig
标签的作用就是设置JAVA_OPTS
变量为JAVA_OPTS
+LOGGING_CONFIG
。( 这里多说一句,我们可以在catalina.bat文件的开始位置添加JAVA_OPTS变量来指定jvm的配置,具体的参数可以自行搜索。)- 继续往下看,比较类似,如果
LOGGING_MANAGER
不为空就转向noJuliManager
标签,否则设置LOGGING_MANAGER
值为-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
noJuliManager
标签,将LOGGING_MANAGER
添加到JAVA_OPTS
变量。
第七部分
rem ----- Execute The Requested Command ---------------------------------------
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=
if not ""%1"" == ""jpda"" goto noJpda
set JPDA=jpda
if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport
set JPDA_TRANSPORT=dt_socket
:gotJpdaTransport
if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress
set JPDA_ADDRESS=8000
:gotJpdaAddress
if not "%JPDA_SUSPEND%" == "" goto gotJpdaSuspend
set JPDA_SUSPEND=n
:gotJpdaSuspend
if not "%JPDA_OPTS%" == "" goto gotJpdaOpts
set JPDA_OPTS=-agentlib:jdwp=transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND%
:gotJpdaOpts
shift
:noJpda
- 打印相关信息,如果第一个参数等于
debug
,转到use_jdk
标签,否则打印相关信息,转向java_dir_displayed
标签,java_dir_displayed
还是打印相关信息。 - 设置
_EXECJAVA
等于变量_RUNJAVA
.(该变量在setclasspath.bat
中设置,值为%JRE_HOME%injava.exe
。 - 设置下相关变量,
MAINCLASS
,ACTION
。清空SECURITY_POLICY_FILE
,DEBUG_OPTS
,JPDA
。 - 如果第一个参数不等于
jpda
,转向noJpda
标签。noJpda
为空标签,因为第一个参数是start
所以,继续往下看
第八部分
if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop
if ""%1"" == ""version"" goto doVersion
echo Usage: catalina ( commands ... )
echo commands:
echo debug Start Catalina in a debugger
echo debug -security Debug Catalina with a security manager
echo jpda start Start Catalina under JPDA debugger
echo run Start Catalina in the current window
echo run -security Start in the current window with security manager
echo start Start Catalina in a separate window
echo start -security Start in a separate window with security manager
echo stop Stop Catalina
echo version What version of tomcat are you running?
goto end
: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%confcatalina.policy"
goto execCmd
:doRun
shift
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%confcatalina.policy"
goto execCmd
:doStart
shift
if not "%OS%" == "Windows_NT" goto noTitle
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
goto gotTitle
:noTitle
set _EXECJAVA=start %_RUNJAVA%
:gotTitle
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%confcatalina.policy"
goto execCmd
:doStop
shift
set ACTION=stop
set CATALINA_OPTS=
goto execCmd
:doVersion
%_EXECJAVA% -classpath "%CATALINA_HOME%libcatalina.jar" org.apache.catalina.util.ServerInfo
goto end
- 一开始就对第一个参数进行判断,进而转向不同的标签,因为我们第一个参数是
start
,所以我们直接就转向了doStart
标签。 doStart
标签,shift
,参数左移,如果当前操作系统不是win
,就转向noTitle
标签,如果Title
变量为空就将Title
设置为Tomcat
,设置_EXECJAVA
变量为start "%TITLE%" %_RUNJAVA%
。- 转向
gotTitle
标签,如果第一个参数不等于-security
,转向execCmd
标签。
执行到这里大概可以看出前面的都是在做准备工作,设置好各种参数,判断等等。终于要开始调用执行命令了。
第九部分
rem 第九部分
:execCmd
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
rem Execute Java with the applicable properties
if not "%JPDA%" == "" goto doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurity
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:end
- 清空
CMD_LINE_ARGS
变量,如果第一个变量为空,转向doneSetArgs
,运行到这里,因为前面在执行doStart
的时候已经执行了shift
命令,所以第一个参数已经是空了,所以直接转向doneSetArgs
标签。 doneSetArgs
为空,所以继续往下执行- 如果
JPDA
变量不为空,转向doJpda
标签,实际上我们在第七部分JPDA
部分的时候基本上是跳过了jpda
,所以该变量是为空的,所以直接继续执行。 - 如果
SECURITY_POLICY_FILE
变量不为空,就转向doSecurity
标签,而实际上理由同上SECURITY_POLICY_FILE
变量也是空的,所以继续往下执行。 -
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
终于等到这一行命令了,参考上面所有的变量这行命令在作者的机器上可以翻译为
start "Tomcat" "D:WorkSoftwareJavajdk1.7.0_13injava" -Djava.util.logging.config.file="E:cccccccccccccccccccccccc omcat7.0conflogging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs="E:cccccccccccccccccccccccc omcat7.0endorsed" -classpath "E:cccccccccccccccccccccccc omcat7.0inootstrap.jar;E:cccccccccccccccccccccccc omcat7.0in omcat-juli.jar" -Dcatalina.base="E:cccccccccccccccccccccccc omcat7.0" -Dcatalina.home="E:cccccccccccccccccccccccc omcat7.0" -Djava.io.tmpdir="E:cccccccccccccccccccccccc omcat7.0 emp" org.apache.catalina.startup.Bootstrap start
这句命令的意思就是新开一个窗口,窗口名字叫做Tomcat 使用java.exe,各种参数配置balabla,最后调用org.apache.catalina.startup.Bootstrap类,(类入口当然是main方法)传递参数为start!!!
总结:
- tomcat启动入口是
startup.bat
文件,该文件会设置CATALINA_HOME
,CATALINA_BASE
等常见变量,并且调用catalina.bat
文件,传递start
参数。 catalina.bat
文件,所做的事情就是检查关键文件是否存在,设置关键变量,例如CATALINA_HOME
,CATALINA_BASE
,classpath
等等,最后新开一个窗口调用Bootstrap
类的main
方法,传递参数start
,并且将一大堆配置传递过去。
所以我们想继续探寻,就需要去Tomcat源码中找寻 Bootstrap类,继续查看相关方法!