Source code analysis of start and stop of spring boot + Dubbo application

Time:2019-11-10

Background introduction
Dubbo spring boot project aims to simplify the development of Dubbo RPC framework in spring boot application scenarios. It also integrates the spring boot feature:

  • Automatic assembly (e.g. annotation driven, automatic assembly, etc.)
  • Production ready (e.g. safety, health check, external configuration, etc.)

Dubboconsumer start analysis

Have you ever thought about a question? The dubboconsumerdemo application in the incregator Dubbo spring boot project is one line of code. After the main method is executed, why doesn’t it exit directly?

Source code analysis of start and stop of spring boot + Dubbo application

In fact, to answer such a question, we first need to abstract this question, that is, a JVM process, under what circumstances will it exit?

Taking Java 8 as an example, by referring to the JVM language specification [1], it is clearly described in Chapter 12.8:

A program terminates all its activity and exits when one of two things happens:

  • All the threads that are not daemon threads terminate.
  • Some thread invokes the exit method of class Runtime or class System,
    and the exit operation is not forbidden by the security manager.

In other words, there are only two situations that lead to the exit of the JVM:

1. All non daemon processes are completely terminated
2. A thread called system. Exit() or runtime. Exit()

Therefore, in view of the above situation, we judge that there must be a non daemon thread that does not exit. We know that we can see all thread information through jstack, including whether they are daemon threads. We can find out those threads that are not Deamon threads through jstack.

Source code analysis of start and stop of spring boot + Dubbo application

Here, all thread summaries are found by grep TID, and rows without the daemon keyword are found by grep-v

Through the above results, we found some information:

  • There are two threads, container-0 and container-1, which are very suspicious. They are non daemon threads and in the wait state
  • There are some GC related threads, VM led threads, and non daemon threads, but they are most likely the JVM’s own threads, which are ignored here for the time being.

In conclusion, we can infer that the JVM did not exit because of container-0 and container-1. Now let’s search the source code to find out who created these two threads.

Through the source code analysis of spring boot, we found the following code in startdaemoniwatthread of org.springframework.boot.context.embedded.tomcat.tomcatembeddedservletcontainer

Source code analysis of start and stop of spring boot + Dubbo application

Add a breakpoint in this method. See call stack:

Source code analysis of start and stop of spring boot + Dubbo application

As you can see, in the process of starting spring boot application, Tomcat exposes HTTP service by default, so the above methods are implemented. All threads started by Tomcat are by default daemon threads, such as acceptor listening to requests, worker thread pool, etc. if there is no control here, the JVM will exit after the start. Therefore, it is necessary to start a thread and wait under certain conditions to avoid thread exit.

Let’s dig deeper into how the thread does not exit in Tomcat’s this. Tomcat. Getserver(). Await(). For the convenience of reading, irrelevant code is removed here.

Source code analysis of start and stop of spring boot + Dubbo application

In the await method, in fact, the current thread checks the stopawait variable every 10 seconds in a while loop. It is a variable of volatile type, which is used to ensure that the current thread can see the change immediately after it is modified by another thread. If there is no change, it will stay in the while loop. This is why the thread does not exit, that is, the whole spring boot application does not exit.

Because the spring boot application starts two ports, 8080 and 8081 (management port), and actually starts two tomcat, there will be two threads, container-0 and container-1.

Next, let’s see how the spring boot application exits?

Dubboconsumer exit analysis

As mentioned in the previous description, there is a thread continuously checking the stopawait variable, so we naturally think that when we stop, there should be a thread to modify the stopawait and break the while loop, so who is modifying the variable?

Through the source code analysis, we can see that only one method has modified stopawait, that is, org.apache.catalina.core.standardserver ා stopawait. Let’s add a breakpoint here to see who is calling.

Note that when we add a breakpoint in the debug mode of IntelliJ idea, we need to use kill – s int $PID or kill – s term $PID on the command line to trigger the breakpoint. Clicking the stop button on the IDE will not trigger the breakpoint. This is a bug of idea

You can see that a thread named thread-3 called this method:

Source code analysis of start and stop of spring boot + Dubbo application

Through the source code analysis, it was originally executed through the shutdownhook registered by spring

Source code analysis of start and stop of spring boot + Dubbo application

By consulting the Java API document [2], we can know that the shutdown hook will execute in the following two cases

The Java virtual machine shuts down in response to two kinds of events:

The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.

1. System. Exit() method called
2. Respond to external signals, such as Ctrl + C (SIGINT signal is actually sent), or SIGTERM signal (SIGTERM signal is sent by kill $PID by default)

Therefore, the normal application will execute the above shutdown hook in the process of stopping (except kill-9 $PID). Its function is not only to shut down tomcat, but also to carry out other cleaning work, which will not be discussed here.

summary

1. During the startup of dubboconsumer, start an independent non daemon thread to check the status of variables to ensure that the process does not exit
2. In the process of dubboconsumer stopping, the state of variables is modified by executing the shutdown hook of spring container, so that the program exits normally

problem

In the example of dubboprovider, we can see that the provider does not start Tomcat to provide HTTP services, so how can we achieve non exit? We will answer this question in the next article.

Egg

Run the following unit test in IntelliJ idea to create a thread to perform the operation of sleeping for 1000 seconds. We are surprised to find that the code exits before the thread finishes executing. Why? (the created thread is a non daemon thread)

Source code analysis of start and stop of spring boot + Dubbo application

[1] https://docs.oracle.com/javas…

[2] https://docs.oracle.com/javas…

Author: middleware brother
Read the original text
This is the original content of yunqi community, which can not be reproduced without permission.