Tomcat series (3) — How does Tomcat start and stop with one click

Before Tomcat is embedded in SpringBoot, we always put the project as a War package in the Tomcat webApp directory, and then run the command start.sh for Linux system, and run the command start.sh for Windows system. After running the command start.bat, you can start up and access the page. Sh or shutdown.bat to stop the application. How does Tomcat start all containers with a single command?

Script analysis

Start. sh and start.bat have the same contents, so this section mainly analyzes the contents of start.sh.

os400=false
case "`uname`" in
OS400*) os400=true;;
esac

# resolve links - $0 may be a softlink
# PRG is the path of the script. If the current script file is a soft connection, the path of the PRG real file will be resolved
PRG="$0"

while [ -h "$PRG"];do Check whether it is a soft connection
  ls=`ls -ld "$PRG"`   If the connection is soft, the output contains Lin -> source string
  link=`expr "$ls" : - > '. * \ \ (. *) $'` The pattern matches the path of the source file
  if expr "$link" : '/. *' > /dev/null; then $link ($link, $link, $link, $link, $link, $link, $link, $link, $link
    PRG="$link"
  else
    PRG=`dirname "$PRG"` /"$link" If no directory is included, the soft connection and the source file are in the same directory
  fi
done

Get the script directory path
PRGDIR=`dirname "$PRG"`
EXECUTABLE=catalina.sh

# Check that target executable exists
if $os400; then
  # -x will Only work on the os400 if the files are:
  # 1. owned by the user
  # 2. owned by the PRIMARY group of the user
  # this will not work if the user belongs in secondary groups
  eval
else
  if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
    echo "Cannot find $PRGDIR/$EXECUTABLE"
    echo "The file is absent or does not have execute permission"
    echo "This file is needed to run this program"
    exit 1
  fi
fi

Run the start command of catalina.sh
exec "$PRGDIR"/"$EXECUTABLE" start "$@"

Copy the code

It does two things in a nutshell

  1. Get the real path to the script
  2. performcatalina.shthestartThe command

Sh is the same as start.sh but is followed by the stop command of catalina.sh

Catalina. Sh scripts

The important steps in the script are the following

  1. Set two important environment variables, CATALINA_HOME and CATALINA_BASE

    PRGDIR=`dirname "$PRG"`
    
    [ -z "$CATALINA_HOME" ] && CATALINA_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`
    
    [ -z "$CATALINA_BASE" ] && CATALINA_BASE="$CATALINA_HOME"
    
    Copy the code
  2. Set the CLASSPATH variable. Note that there is no setenv.sh file by default

    CLASSPATH=
    
    if [ -r "$CATALINA_BASE/bin/setenv.sh" ]; then
      . "$CATALINA_BASE/bin/setenv.sh"
    elif [ -r "$CATALINA_HOME/bin/setenv.sh" ]; then
      . "$CATALINA_HOME/bin/setenv.sh"
    fi
    
    Copy the code
  3. Pass in bootstrap.jar as the CLASSPATH variable

    if [ ! -z "$CLASSPATH"];then
      CLASSPATH="$CLASSPATH":
    fi
    CLASSPATH="$CLASSPATH""$CATALINA_HOME"/bin/bootstrap.jar
    
    if [ -z "$CATALINA_OUT"];then
      CATALINA_OUT="$CATALINA_BASE"/logs/catalina.out
    fi
    
    Copy the code
  4. Execute the script arguments by executing the main method of the bootstrap class in bootstrap.jar and passing in the start argument

        shift
        eval exec "\"$_RUNJAVA\ "" "\"$LOGGING_CONFIG\ "" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
          -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\ "" \
          -classpath "\"$CLASSPATH\ "" \
          -Djava.security.manager \
          -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \
          -Dcatalina.base="\"$CATALINA_BASE\ "" \
          -Dcatalina.home="\"$CATALINA_HOME\ "" \
          -Djava.io.tmpdir="\"$CATALINA_TMPDIR\ "" \
          org.apache.catalina.startup.Bootstrap "$@" start
    
    Copy the code

In the above script, we can see that the last execution is from the main method of Bootstrap as the entry, so we open the Tomcat source code into the Bootstrap class to see what it does.

Priming class analysis

As an entry class for Tomcat, let’s take a look at what we do in Bootstrap. Only the important code in the main method is posted here.

Bootstrap.init (); // Initialize the classloader and load the Catalina file into memory. Stringcommand = "start";
if (args.length > 0) {
    command = args[args.length - 1];
}

if (command.equals("startd")) {
    args[args.length - 1] = "start"; // Call daemon.load(args) of Catalina.java; // Call daemon.start() for catalina.java; }else if (command.equals("stopd")) {
    args[args.length - 1] = "stop"; // Call catalina.java stop daemon.stop(); }else if (command.equals("start")) {
    daemon.setAwait(true);
    daemon.load(args);
    daemon.start();
    if(null == daemon.getServer()) { System.exit(1); }}else if (command.equals("stop")) {
    daemon.stopServer(args);
} else if (command.equals("configtest")) {
    daemon.load(args);
    if (null == daemon.getServer()) {
        System.exit(1);
    }
    System.exit(0);
} else {
    log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
Copy the code

Here are different methods called Catalina based on the commands passed in from the script. Since we mainly analyze how Tomcat can start and stop with one click, we mainly analyze Catalina’s start method.

We see this in Catalina’s SATRT method

getServer().start();

Copy the code

Subsequent debugging will be done with the Start method for Lifecycle, which will be listed

public interface Lifecycle {

    public void addLifecycleListener(LifecycleListener listener);

    public LifecycleListener[] findLifecycleListeners();

    public void removeLifecycleListener(LifecycleListener listener);

    public void init() throws LifecycleException;

    public void start() throws LifecycleException;

    public void stop() throws LifecycleException;

    public void destroy() throws LifecycleException;

    public LifecycleState getState();

    public String getStateName();

    public interface SingleUse {
    }
}

Copy the code

Then looking at its implementation class, we see that all the components in the overall architecture we talked about earlier implement this class. Its subclass LifecycleBase implements start, init, stop and other methods, and calls startInternal, initInternal, stopInternal methods accordingly. One might imagine that the template design pattern is applied here, abstracting out the public code of all subclasses, and then redefining an internal abstraction method whose subclasses implement their own custom operations.

In server.xml we found that the first tier was also a Server, and then Catalina’s SATRT method started the first Server.

The above shows the hierarchy of all Tomcat modules. As long as there is a hierarchy, we should be able to immediately think of the composite design pattern. From this hierarchy we can get the relationship between modules, big and small, inside and outside.

  • Big and small: Big components manage widgets, such as Servers manage Services, and services manage connectors and containers
  • Inside and out: Connectors control external connections, while outer components call inner components to perform business functions. That is, the request processing process is driven by the outer component.

So, according to the above two, we know that there is small to have big, there is inside to have outside. This is the loading order of the whole hierarchy: small components first, then large components, inner components first, then outer components. This should give you an idea of how Tomcat can start and stop with one click. By hierarchy, load priority. Layers of iteration are initiated. And stopping is pretty much the same as starting. It’s also a layer of iteration that stops.

The articles

How to debug Tomcat source code breakpoint

Tomcat Series 1 — Overall architecture

Tomcat series 2 – EndPoint source code parsing

A weird trip to find StackOverflowError problems

A simple RPC framework for hand – to – hand

A Simple RPC Framework (2) – Project transformation

Refer to the article

  • Expr command instance
  • Tomcat running script and Startup process analysis catalina.sh