• Tomcat启动过程源码分析一


    前言

      我们都知道只需要在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做了说明。

    正式代码开始在标注第二部分的地方开始。

    1. 设置变量CURRENT_DIR为当前目录,例如你打开了tomcatbin目录,那么CURRENT_DIR就指向了bin目录。
    2. 判断系统变量CATALINA_HOME如果不是空串,那么就跳转到gotHome标签执行,实际上我们很少去设置CATALINA_HOME这个系统变量,所以我们继续往下看。
    3. 设置CATALINA_HOMECURRENT_DIR指向的目录,也就是bin目录。
    4. 判断CATALINA_HOMEincatalina.bat文件是否存在,如果存在就转向okHome标签,明显CATALINA_HOME现在指向的是bin目录,那么binincatalina.bat文件是不存在的,所以继续往下看,不会跳转到okHome
    5. cd..退出到上一级目录
    6. 设置CATALINA_HOME指向当前目录,也就是Tomcat的根目录。
    7. 进入CURRENT_DIR指向的目录,也就是bin

    继续看标注第三部分的地方的代码。

    1. 执行gotHome标签。
    2. 如果存在CATALINA_HOME%incatalina.bat这个文件就跳转执行okHome标签。

    继续看标注第四部分的地方的代码。

    1. 设置变量EXECUTABLE指向catalina.bat文件

    继续看标注第五部分的地方的代码。

    1. 双重保险继续判断下EXECUTABLE指向的catalina.bat文件是否存在。存在就跳转执行okExec标签。

    继续看标注第六部分的地方的代码。

    1. set CMD_LINE_ARGS=表示清空变量CMD_LINE_ARGS
    2. 执行setArgs标签
    3. 第一个变量(%1%)为空字符串,那么就跳转到doneSetArgs标签,因为我们是直接运行startup.bat,没有传递任何参数,所以我们应该是跳转到doneSetArgs标签,由此也可以猜想出,如果不是使用双击执行的话,使用命令行启动startup.bat那么是可以传递参数的。
    4. 跳转到doneSetArgs,调用EXECUTABLE指向的文件,也就是catalina.bat文件,同时传递 start参数,因为CMD_LINE_ARGS为空,所以只传递了一个start参数

    第七部分

    1. 可以看出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
    
    1. if not ""%1"" == ""run"" goto mainEntry:第一个参数不是run,就转向mainEntry标签,我们传递的第一个参数从上面来看是start,所以直接看mainEntry标签。

    2. 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
    
    1. 设置CURRENT_DIR为当前目录bin(假如你是在bin目录中启动)
    2. CATALINA_HOME不是空就转向okHome
    3. 设置CATALINA_HOME指向CURRENT_DIR的目录,也就是bin目录。
    4. 如果存在%CATALINA_HOME%incatalina.bat,那么就转向okHome,否则退出到父目录,(显然不存在binincatalina.bat)
    5. 设置CATALINA_HOME为当前目录(也就是Tomcat的根目录)
    6. 进入CURRENT_HOME指向的目录,也就是bin目录,执行gotHome标签
    7. 如果存在%CATALINA_HOME%incatalina.bat,就转向okHome,现在CATALINA_HOME指向的目录是Tomcat的安装目录,所以incatalina.bat文件是存在的,所以转向okHome标签。
    8. 如果CATALINA_BASE变量不是空,就转向gotBase标签。(显然为空)
    9. 设置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
    
    1. 清空CLASSPATH
    2. 如果不存在%CATALINA_BASE%insetenv.bat文件,那么就转向checkSetenvHome标签,我们现在使用的是apache-tomcat-7.0.67,该文件是不存在的,所以转向checkSetenvHome标签。
    3. checkSetenvHome标签,如果存在%CATALINA_HOME%insetenv.bat,那么就调用%CATALINA_HOME%insetenv.bat文件,显然依旧不存在。
    4. 继续执行goto gotSetenvBasegotSetenvBase标签为空,继续往下执行。

    第四部分

    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
    
    1. 如果存在%CATALINA_HOME%insetclasspath.bat,那么就转向okSetclasspath标签,(显然存在)
    2. 设置BASEDIR指向CATALINA_HOME
    3. 调用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
    
    1. 如果CLASSPATH变量为空,就跳转到emptyClasspath标签,由上面能看出来,CLASSPATH变量的确是空的,所以跳转到emptyClasspath标签。
    2. 设置CLASSPATH指向%CLASSPATH%%CATALINA_HOME%BINBOOTSTRAP.JAR(也就是TOMCAT安装目录下BINBOOTSTRAP.JAR)。
    3. 如果CATALINA_BASE不为空(这里是为空)那么转向gotBase标签,gotBase为空标签,继续往下执行,设置CATALINA_BASE等于CATALINA_HOME
    4. 如果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%
    
    1. 如果不存在%CATALINA_BASE%in omcat-juli.jar那么就跳转到juliClasspathHome标签,我们使用的tomcat版本是存在的,所以继续执行。
    2. 该命令set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%in omcat-juli.jar"表示将tomcat-juli.jar的路径添加到CLASSPATH中。
    3. 跳转juliClasspathDone标签,juliClasspathDone是空标签
    4. 继续执行,如果LOGGING_CONFIG变量不为空就跳转到noJuliConfig标签,否则这只LOGGING_CONFIG=-Dnop
    5. 如果不存在%CATALINA_BASE%conflogging.properties,那么就跳转noJuliConfig标签,否则设置LOGGING_CONFIG等于-Djava.util.logging.config.file="%CATALINA_BASE%conflogging.properties"
    6. noJuliConfig标签的作用就是设置JAVA_OPTS变量为JAVA_OPTS+LOGGING_CONFIG。( 这里多说一句,我们可以在catalina.bat文件的开始位置添加JAVA_OPTS变量来指定jvm的配置,具体的参数可以自行搜索。)
    7. 继续往下看,比较类似,如果LOGGING_MANAGER不为空就转向noJuliManager标签,否则设置LOGGING_MANAGER值为-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
    8. 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
    
    1. 打印相关信息,如果第一个参数等于debug,转到use_jdk标签,否则打印相关信息,转向java_dir_displayed标签,java_dir_displayed还是打印相关信息。
    2. 设置_EXECJAVA等于变量_RUNJAVA.(该变量在setclasspath.bat中设置,值为%JRE_HOME%injava.exe
    3. 设置下相关变量,MAINCLASSACTION。清空SECURITY_POLICY_FILEDEBUG_OPTSJPDA
    4. 如果第一个参数不等于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
    
    1. 一开始就对第一个参数进行判断,进而转向不同的标签,因为我们第一个参数是start,所以我们直接就转向了doStart标签。
    2. doStart标签,shift,参数左移,如果当前操作系统不是win,就转向noTitle标签,如果Title变量为空就将Title设置为Tomcat,设置_EXECJAVA变量为start "%TITLE%" %_RUNJAVA%
    3. 转向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
    
    1. 清空CMD_LINE_ARGS变量,如果第一个变量为空,转向doneSetArgs,运行到这里,因为前面在执行doStart的时候已经执行了shift命令,所以第一个参数已经是空了,所以直接转向doneSetArgs标签。
    2. doneSetArgs为空,所以继续往下执行
    3. 如果JPDA变量不为空,转向doJpda标签,实际上我们在第七部分JPDA部分的时候基本上是跳过了jpda,所以该变量是为空的,所以直接继续执行。
    4. 如果SECURITY_POLICY_FILE变量不为空,就转向doSecurity标签,而实际上理由同上SECURITY_POLICY_FILE变量也是空的,所以继续往下执行。
    5.   %_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!!!

    总结:

    1. tomcat启动入口是startup.bat文件,该文件会设置CATALINA_HOME,CATALINA_BASE等常见变量,并且调用catalina.bat文件,传递start参数。
    2. catalina.bat文件,所做的事情就是检查关键文件是否存在,设置关键变量,例如CATALINA_HOME,CATALINA_BASE,classpath等等,最后新开一个窗口调用Bootstrap类的main方法,传递参数start,并且将一大堆配置传递过去。

    所以我们想继续探寻,就需要去Tomcat源码中找寻 Bootstrap类,继续查看相关方法!

  • 相关阅读:
    重定向URL
    【有意思的BUG】分享按钮 分享功能
    【有意思的BUG】浏览器的Title和Icon
    【有意思的BUG】需要停止的进程
    【NO.8】jmeter-场景-上传文件-send-a-file
    nmon-监控测试服务器
    SecureCRT-转换密钥-Xshell-配置服务-使用xshell登录远程linux服务器
    <转>【读fastclick源码有感】彻底解决tap“点透”,提升移动端点击响应速度
    javascript判断鼠标按键和键盘按键的方法
    javascript 中几种实用的跨域方法原理详解(转)
  • 原文地址:https://www.cnblogs.com/coldridgeValley/p/5471421.html
Copyright © 2020-2023  润新知