SoFunction
Updated on 2025-03-08

Parse Tomcat's startup script--

Overview

The three most important startup scripts for Tomcat:

Previous articleWe analyzed the script

Let's analyze the script in this article.

As for this script, I believe that after reading this article, I can understand this script by myself.
You can click to download [script]View the commented script

There is a lot of code in this script, so I made a separate article to display the contents in the script. Click [script]Download to view.

Let’s analyze it line by line according to the content in the script.

@echo off
setlocal

These two commands can be found in the previous article (Parse Tomcat's startup script--) Explanation

The first script code

rem Suppress Terminate batch job on CTRL+C
if not ""%1"" == ""run"" goto mainEntry
if "%TEMP%" == "" goto mainEntry
if exist "%TEMP%\%~" goto mainEntry
echo Y>"%TEMP%\%~"
if not exist "%TEMP%\%~" goto mainEntry
echo Y>"%TEMP%\%~"
call "%~f0" %* <"%TEMP%\%~"
rem Use provided errorlevel
set RETVAL=%ERRORLEVEL%
del /Q "%TEMP%\%~" >NUL 2>&1
exit /B %RETVAL%
:mainEntry
del /Q "%TEMP%\%~" >NUL 2>&1

The role of scripts

Determine whether the user is using it

run

To start Tomcat.

If the user starts Tomcat with a script, the script will not be executed.

This code looks messy, so analyze it slowly.

First line:

Comments, meaning: CTRL+C is prohibited from using CTRL+C to terminate batch tasks, and I don’t know how it is prohibited.

Line 2:

if not ""%1"" == ""run"" goto mainEntry

First of all, understand what the "%1" variable here represents? Under normal circumstances, this script is called by a script, and when it is called, a start parameter is passed (derived from the previous analysis). In the batch command, %1 represents the first parameter after the command, which refers to start here. So "%1" = start. If the user starts Tomcat with the run command, then "%1" = run here.

Line 3:

if "%TEMP%" == "" goto mainEntry

The %TEMP% here is likely to be considered empty, but in fact, the system's environment variable can be read here. Therefore, the %TEMP% here is the system's environment variable value. Usually, after installing the Windows system, the system will automatically configure this environment variable. So there are usually values ​​here. You can go to the system's environment variable to see which directory it points to, which is generally C:\Users\username\AppData\Local\Temp. Note: AppData is a hidden directory.

Line 4:

if exist "%TEMP%\%~" goto mainEntry

Here is another new thing %~nx0. In batch processing, we know that %1 represents the first parameter after the program, so what about %0? %0 represents the name of this executable program. If %~nx0 is the name of the program + the extension

Here is it. You can write a small script () to verify it: (My script is placed under D disk)

Script content:

@echo off
echo "%~nx0"
echo "%1"

Execution results:

PS D:\> .\ Hello
""
"Hello"
PS D:\>

The fifth element:

echo Y>"%TEMP%\%~"

This code is very simple, it is to write the character Y into the %TEMP%\ file.

Line 6:

if not exist "%TEMP%\%~" goto mainEntry

I also judged whether the %TEMP%\ file exists.

Line 7:

echo Y>"%TEMP%\%~"

In the same fifth line, write Y to %TEMP%\. If the file does not exist, create a new one.

Line 8:

call "%~f0" %* <"%TEMP%\%~"

This line is interesting. Two new things have appeared:

(Because of the markdown syntax limitation, write the following code into the code block)

- "%~f0" : Simply put, it means the absolute path of the current command.
- "%*" : We know that %1 represents the first parameter, and so on, %2 represents the second... Then %* is easy to understand, representing all parameters.

Verify

Script content:

@echo off
echo "%*"
echo "%~f0"

Execution results:

PS D:\> .\ Hello World
"Hello World"
"D:\"
PS D:\>

Then the following <"%TEMP%\%~" means reading the contents in the %TEMP%\ file.

Then it is called through call.

Let's write an example ourselves, create a file on disk D, and then create a file

Script content:

call "%~f0" %* < D:/

File content

Y

Execution results:

........
D:\>call "D:\" Hello World 0<D:/
D:\>call "D:\" Hello World 0<D:/
D:\>call "D:\" Hello World 0<D:/
D:\>call "D:\" Hello World 0<D:/
D:\>call "D:\" Hello World 0<D:/
D:\>call "D:\" Hello World 0<D:/
D:\>call "D:\" Hello World 0<D:/
****** B A T C H R E C U R S I O N exceeds STACK limits ******
Recursion Count=593, Stack Usage=90 percent
****** B A T C H PROCESSING IS A B O R T E D ******

A lot of duplicate code is omitted at the top, and from here it finds that it keeps calling itself until it exceeds the limit of the stack.

If we add @echo off

@echo off
call "%~f0" %* < D:/

The result will only appear

D:\>.\ Hello World
****** B A T C H R E C U R S I O N exceeds STACK limits ******
Recursion Count=593, Stack Usage=90 percent
****** B A T C H PROCESSING IS A B O R T E D ******

We only need to understand the role of these commands here. We will summarize the purpose of Tomcat's execution of these commands later.

Line 10:

set RETVAL=%ERRORLEVEL%

If we know Linux, we all know that the execution of each command will return an exit code after execution. After Linux executes a command, use echo $? to view the exit code of the previous command. The same is true in Windows, and the command has its own exit code after execution. The %ERRORLEVEL% here is the exit code of the call command above. Assign it to a variable RETVAL

Line 11:

del /Q "%TEMP%\%~" >NUL 2>&1

Another del command appears here, which is easy to associate with delete. So what does /Q mean? Silent deletion will not give you any prompts, just like rm -f in Linux, here is to delete the %TEMP%\ file.

What does the following >NUL 2>&1 mean?

The principle of redirecting the output stream in Linux is the same.

(Because of the markdown syntax limitation, write the following code into the code block)

- &gt;NUL : Indicates redirecting the output to NUL middle, You can't see anything
- 2&gt;&amp;1 : 2:Error output, &amp;1: Standard output, 意思就是将错误消息输出到Standard outputmiddle.
- &gt;NUL 2&gt;&amp;1 : 就是先将错误消息输出到Standard outputmiddle, Then output to NUL middle.

Line 12:

exit /B %RETVAL%

Exit the current batch process, /B specifies the number at the time of exit, and sets the RETVAL most exit code, which is the exit code of the command executed by call.

The last two lines:

:mainEntry
del /Q "%TEMP%\%~" >NUL 2>&1

Define a mainEntry tag and then delete the files in the temporary directory.

Summarize the functions of the first script

Simply put, the function of this code is to call itself, to judge whether the files in the temporary directory exist to avoid the secondary callback itself. It feels like the writing is very complicated.

Let’s enter the official startup process of Tomcat, and the main method is not started.

The second script code

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\" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%\bin\" 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 Copy CATALINA_BASE from CATALINA_HOME if not defined
if not "%CATALINA_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase

This script is relatively simple, mainly setting two environment variables: CATALINA_HOME and CATALINA_BASE.

If the CATALINA_BASE environment variable is not configured, directly refer to the value of CATALINA_HOME

Calm down and take a look at it and you will understand.

The third script code

rem Ensure that neither CATALINA_HOME nor CATALINA_BASE contains a semi-colon
rem as this is used as the separator in the classpath and Java provides no
rem mechanism for escaping if the same character appears in the path. Check this
rem by replacing all occurrences of ';' with '' and checking that neither
rem CATALINA_HOME nor CATALINA_BASE have changed
if "%CATALINA_HOME%" == "%CATALINA_HOME:;=%" goto homeNoSemicolon
echo Using CATALINA_HOME: "%CATALINA_HOME%"
echo Unable to start as CATALINA_HOME contains a semicolon (;) character
goto end
:homeNoSemicolon
if "%CATALINA_BASE%" == "%CATALINA_BASE:;=%" goto baseNoSemicolon
echo Using CATALINA_BASE: "%CATALINA_BASE%"
echo Unable to start as CATALINA_BASE contains a semicolon (;) character
goto end
:baseNoSemicolon

Here we mainly judge whether the values ​​of the CATALINA_HOME environment variable and the values ​​of the CATALINA_BASE environment variable end with a semicolon. If they end with a semicolon, an error will be reported and exited.

Fourth script code

rem Ensure that any user defined CLASSPATH variables are not used on startup,
rem but allow them to be specified in , in rare case when it is needed.
set CLASSPATH=
rem Get standard environment variables
if not exist "%CATALINA_BASE%\bin\" goto checkSetenvHome
call "%CATALINA_BASE%\bin\"
goto setenvDone
:checkSetenvHome
if exist "%CATALINA_HOME%\bin\" call "%CATALINA_HOME%\bin\"
:setenvDone
rem Get standard Java environment variables
if exist "%CATALINA_HOME%\bin\" goto okSetclasspath
echo Cannot find "%CATALINA_HOME%\bin\"
echo This file is needed to run this program
goto end
:okSetclasspath
call "%CATALINA_HOME%\bin\" %1
if errorlevel 1 goto end

Set a temporary environment variable: CLASSPATH.

If a script exists under the bin directory of Tomcat, execute it. Usually there is no.

Then we will determine whether the script exists. If it does not exist, an error will be reported directly and the Tomcat will be stopped.

If it exists, call it and pass the first parameter in.

This script mainly sets several environment variables

  • JAVA_HOME
  • JRE_HOME
  • JAVA_ENDORSED_DIRS = %CATALINA_HOME%\endorsed
  • _RUNJAVA = %JRE_HOME%\bin\
  • _RUNJDB = %JAVA_HOME%\bin\

The fifth script code

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%\bin\"
if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set "CATALINA_TMPDIR=%CATALINA_BASE%\temp"
:gotTmpdir
rem Add  to classpath
rem  can be over-ridden per instance
if not exist "%CATALINA_BASE%\bin\" goto juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\"
goto juliClasspathDone
:juliClasspathHome
set "CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\"
:juliClasspathDone

This code mainly does three things:

  • Add the Tomcat bin directory to the environment variable
  • Set the value of the CATALINA_TMPDIR environment variable to the temp directory under the Tomcat directory
  • Add the Tomcat bin directory to the environment variable

Sixth script code

if not "%JSSE_OPTS%" == "" goto gotJsseOpts
set JSSE_OPTS="-=2048"
:gotJsseOpts
set "JAVA_OPTS=%JAVA_OPTS% %JSSE_OPTS%"
rem Register custom URL handlers
rem Do this here so custom URL handles (specifically 'war:...') can be used in the security policy
set "JAVA_OPTS=%JAVA_OPTS% -="
if not "%LOGGING_CONFIG%" == "" goto noJuliConfig
set LOGGING_CONFIG=-Dnop
if not exist "%CATALINA_BASE%\conf\" goto noJuliConfig
set LOGGING_CONFIG=-="%CATALINA_BASE%\conf\"
:noJuliConfig
set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%"
if not "%LOGGING_MANAGER%" == "" goto noJuliManager
set LOGGING_MANAGER=-=
:noJuliManager
set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%"

It mainly adds a series of startup parameters to the JAVA_OPTS environment variable.

Eighth script code

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%"

It mainly prints relevant environment variable information.

The ninth script code

set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBUG_OPTS=
set JPDA=

Set some columns of environment variables:

  • _RUNJAVA : %JRE_HOME%\bin\
  • MAINCLASS: Specifies the startup class of Tomcat. Yes, the main method is in this class.
  • ACTION: Action: It is to start
  • SECURITY_POLICY_FILE: Security policy file. If the -security parameter is added at startup, the following will specify this parameter to the file in the conf directory of Tomcat.
  • JPDA: This parameter can be used on Baidu, but we can hardly use it normally.

The tenth code

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=localhost: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

It seems that I jumped directly from the first line to the last line. Yes, usually if I don’t add jpda parameters when I didn’t start, I will skip it directly here. The scripts inside are about JPDA settings, etc.

11 script code

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
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 configtest Run a basic syntax check on 
echo version What version of tomcat are you running?
goto end

It's like a switch switch.

  • If we start Tomcat with
  • If Tomcat is started with run, the value of "%1" here is run

12th script code

:doRun
shift
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\"
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\"
goto execCmd

First, analyze two of the shift commands

The first shift removes the start or run parameters, and then uses "%1" to get the parameters. At this time, the second one in the parameter list is taken.

The second shift is removed in the second parameter.

Let's compare the differences between start and run.

difference

if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
  • If the script is started, a new cmd window will be started and the cmd title is set to Tomcat.
  • If run starts, the cmd window will not be created, nor will the cmd title be set.

Finally, they all jumped to the execCmd tag.

Thirteenth script code

: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

Here we use "%1" to retrieve the parameters after the startup command. If stored, add them to the CMD_LINE_ARGS environment variable and remove this parameter.

Normally, we will not have any parameters here, and we will not append the -security parameter.

Keep going down.

Fourteenth script code

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% -="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -="%CATALINA_BASE%" -="%CATALINA_HOME%" -="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end

Obviously, our %JPDA% has no value and will not jump; since we did not add the -security parameter, %SECURITY_POLICY_FILE% has no value and will not jump.

The following long command is to start the BootStrap class and pass the corresponding parameters in.

Just replace the corresponding environment variables with their values ​​and parse the content of this long command. I believe you can. Be patient!

Let's summarize

  1. First, let’s judge that the user directly uses run to start Tocmat
  2. Set the CATALINA_HOME and CATALINA_BASE environment variable values
  3. Verify the correctness of the CATALINA_HOME and CATALINA_BASE environment variable values
  4. Call script
  5. Call script
  6. Add and to CLASSPATH
  7. Set the value of the CATALINA_TMPDIR temporary directory to temp in the Tomcat directory
  8. Append a series of parameters to JAVA_OPTS
  9. Integrate relevant startup information, parameters
  10. Start Tomcat

The above is the entire content of this article. I hope that the content of this article will be of certain help to everyone's study or work. Friends who are interested can read the previous article "Parse Tomcat's startup script-