In this paper, starting from vivo Internet technology WeChat public links: mp.weixin.qq.com/s/ZqkmoAR4J… Author: Ma Yunjie

By reading the source code of the Tomcat startup and shutdown process, this article provides an in-depth analysis of the principles behind the different Tomcat shutdown methods, so that developers can understand what needs to be paid attention to when using different shutdown methods and avoid unexpected errors caused by unexpected JVM process exits.

First, Tomcat startup process

To understand how Tomcat is shut down, first take a look at how Tomcat is started. Here’s a brief introduction.

The entry point for Tomcat startup is the main method in the Bootstrap class. After that, server, Service, Enigin, Connector, Host, Context and other components are initialized according to the configuration in server.xml, and then these components are started. Let’s focus on what Tomcat does once it’s started.

After each component of Tomcat is started, the main thread enters the await() method of Catalina.out, which in turn calls the await() method of the Server component. As the name suggests, the purpose of this method is to block the current thread (the main thread).

Analyze the source code of await (the source code is long, part of it is captured here, all of it can be read by pulling the Tomcat source code).



(StandardServer. Await ())

We find that the await() method mainly does the following based on the setting of the server node port property in server.xml:

  • When port is -2, the function exits and the main thread is not blocked.

  • With port -1, the waiting thread is set to the current thread and a while loop is entered until the stopAwait flag position is true

  • If port is other, a new socket server is created, which binds the IP address of the current server and port port. Then, the waiting thread is set to the current thread, and the socket enters the blocking listening state. Until the socket listens for a preset SHUTDOWN string in server.xml (default: “SHUTDOWN”)

After the main thread exits the wait, the Tomcat shutdown process is started to stop and destroy each component. As you can see from the above analysis, to stop Tomcat, you need to break the wait state of the main thread.

The following figure shows the entire Tomcat life cycle.



(Tomcat life cycle)

Common ways to shut down Tomcat

1. In the bin directory of the Downloaded Tomcat package, there is an official script (shutdown.sh) to end the Tomcat process.

2, on the server, we can also use the kill -x command to end the Tomcat process.

3. In addition, the occurrence of anomalies such as system.exit () and OOM in the code will also lead to the shutdown of the Tomcat process, but these two are not normal operation and maintenance methods, so we will not analyze them here.

The shutdown script

1. Principle of shutdown.sh

Sh and catalina.sh scripts are used to call the main method of the Bootstrap class. The difference is that “stop” is passed as the parameter of the main method. The main method passed this parameter calls the stopServer() method of the Catalina class. Here we erase unnecessary code and simplify the stopServer() method into the following four steps:



It mainly does two things:

  • XML file, and then initialize Tomcat component member variables according to the attributes in server. XML. Here we focus on several Server component member variables: The default values of port, address, and shutdown are 8005, 127.0.0.1, and shutdown respectively. The values must be the same as those of server. XML read during startup.

  • Generates a SHUTDOWN string for the Socket port that the Address port is listening on.

At this point, it’s obvious that this corresponds to the third blocking case in section 1, where the “SHUTDOWN” string terminates the wait state for the main thread and then releases the resource by calling each component’s stop() and destroy() methods.

2. Disadvantages of the Shutdown script

Although the Shutdown script is officially produced by Tomcat, it is not widely used in practical applications, mainly due to the following two shortcomings:

  • This allows anyone to shutdown the Tomcat process by sending the “shutdown” string to the corresponding port, which can be very dangerous in a production environment. Therefore, in production environments, the port attribute of the Server is set to -1

  • The shutdown script simply ends the wait state of the main thread and allows it to proceed normally. As we know, threads in the JVM are divided into daemons and user threads. Daemons are automatically retracted after all user threads have finished, causing the JVM process to exit. The main thread is a user thread, but as the program becomes more complex, there may be many other user threads. Such as our normal development process, the operation of the commonly used to create a thread pool Executors. NewFixedThreadPool (n) will create n user threads and the threads in the main after the main thread, does not automatically recycling, thus prevent the JVM the normal exit. As a result, the shutdown script is often invoked, but the Tomcat process cannot exit.

Fourth, kill x

1, kill -9 or kill -15

The kill -x operation in Linux sends the corresponding semaphore to the target process. You can use the kill -l command to view the semaphore value represented by each value.



(Kill semaphore)

In this case, we often use the kill-9 command. Kill -9 forces the current process to end immediately, which is both convenient and destructive. In the actual environment, we may have running tasks. If the program is forced to close at this time, the data of the current task will be lost, especially the task with a very long time, and the previous efforts may be wasted. At the same time, if the program is improperly designed and there is no corresponding idempotent operation, it may cause data loss or dirty data generation in the actual environment, which will cause fatal problems in the production environment.

Compared to kill -9, kill -15 (15 is just an example; there are other interrupt signals in Linux) is much more elegant. Kill -15 is an interrupt semaphore sent to the process for one TERM. Upon receipt of this semaphore, the JVM responds with an interrupt and terminates the current process. The reason this gracefully shuts down Tomcat is that the JVM starts a series of threads called Shutdownhooks before terminating the current process, and these threads become our risk control tools. Let’s first look at the closing hooks in Tomcat.

2. Shutdownhook

Tomcat’s closed hook is defined in the Catalina class. There is an inner class called CatalinaShutdownHook that inherits Thread. Following the run() method in this thread class, it calls Catalina’s stop() method, which, in addition to stopping components normally, interrupts and quickly terminates the main thread (if it still exists). Finally, the component’s destroy() method is called to release the resource.



(Shutdownhook in Tomcat)

In addition to Tomcat’s use of closing hooks, many middleware also use this very important feature.

We can also use closed hooks in normal development process. We can add hooks by calling Runtime.geTruntime ().addShutdownhook (shutdownHook) during program startup or Runtime. However, it should be noted that: Code to remove hooks needs to be added to the closed process.

Spring certainly has applications for closing hooks, and it also provides a much friendlier programming experience for using closed hooks.

In Spring, shut off the hook is in AbstractApplicationContext registerShutdownHook () method to add the code in (below), and its close hooks run method will be called destroyBeans () method, It calls its destroy() method on all classes that inherit the DisposableBean interface.

If you have the need to close the hook, you can inherit to DisposableBean, and destroy() to conveniently recycle resources and clean up the battlefield.



3. Note the use of Shutdownhook

Shutdownhook in use is not free to use, need to pay attention to the following points:

  • Shutdownhook calls are not guaranteed to be sequential

  • Shutdownhook is the thread that is invoked before the JVM terminates, so methods in this thread should be kept as short as possible and should not be deadlocked, which would prevent the JVM from exiting properly

  • System.exit() cannot be executed in Shutdownhook, otherwise the virtual machine will freeze and the process will have to be forcibly killed

Five, the summary

In this paper, the principles of the two common shutdown modes of Tomcat are studied. From the above analysis, it can be seen that using shutdown.sh script to control the shutdown mode of Tomcat has permission risks and Tomcat cannot be shutdown due to thread operations in development, so this method is rarely used in practical applications.

Kill -15 can safely kill the Tomcat process, and thanks to the JVM Shutdownhook, we can have stronger control over the entire program when closing, and the exit process is more elegant, so it is widely used.

For more content, please pay attention to vivo Internet technology wechat public account

Note: To reprint the article, please contact our wechat account: LABs2020.