Author: Yellow lazuli

Source: Blogland

preface

When using Springboot, it is necessary to stop and start the service. When we stop the service, most of the time we kill the process directly by killing -9, so that the program will not perform graceful shutdown. And some unfinished programs will simply exit.

Most of the time, we need to safely shut down the service, that is, to finish the unfinished work. For example, it is necessary to stop some dependent services, output some logs, and send some signals to other application systems to ensure the high availability of the system. So let’s look at some ways to stop the Springboot service.

Methods a

The first one is the function of the Actuator provided by Springboot. It can perform shutdown, health, info, etc. By default, the shutdown of the actuator is disabled and we need to turn it on. The maven dependency for Acturator is introduced first.

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>Copy the code

Then open the shutdown node and use /actuator/shutdown to expose web access. In addition to shutdown and health, the info web access to open the word management endpoints. Web. Exposure. Include = *. Add the following configuration to application.properties. Set the service port number to 3333.

server.port=3333
management.endpoint.shutdown.enabled=true
management.endpoints.web.exposure.include=shutdownCopy the code

Next, let’s create a SpringBoot project, then set up a bean object and configure the PreDestroy method. This prints the statement when it stops. The entire life cycle of a bean is created, initialized, destroyed, and destroyed when it is finally closed. Execute an output log in the destroy method.

package com.hqs.springboot.shutdowndemo.bean; import javax.annotation.PreDestroy; /** * @author huangqingshi * @Date 2019-08-17 */ public class TerminateBean { @PreDestroy public void preDestroy() { System.out.println("TerminalBean is destroyed"); }}Copy the code

Make a Configuration and provide a method to get the bean so that the bean object will be initialized.

package com.hqs.springboot.shutdowndemo.config;

import com.hqs.springboot.shutdowndemo.bean.TerminateBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author huangqingshi
 * @Date 2019-08-17
 */
@Configuration
public class ShutDownConfig {

    @Bean
    public TerminateBean getTerminateBean() {
        return new TerminateBean();
    }

}Copy the code

In the startup class output a startup log, when the project starts, we will see the startup output, then execute the stop command.

curl -X POST http://localhost:3333/actuator/shutdownCopy the code

The following logs can output log prints when started and when stopped, while the program has stopped. Isn’t it amazing?

Method 2

The second method is also simpler: get the program startup context and close the main program startup context. This also calls the PreDestroy annotation when the program is closed. The following method is used to close the program ten seconds after it starts.

 /* method 2: use ctx.close to shutdown all application context */
ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.class, args);

try {
        TimeUnit.SECONDS.sleep(10);

 } catch (InterruptedException e) {
            e.printStackTrace();
 }

 ctx.close();Copy the code

Methods three

The third method, at the time of springboot start writing process, in an app. The pid file, the generated path can be specified, can through the command cat/Users/huangqingshi/app. Id | xargs directly kill command to stop the service, The bean object’s PreDestroy method is also called at this point. This method is widely used. Write a start.sh to start the Springboot program, and then write a stop program to stop the service.

/* method 3 : generate a pid in a specified path, while use command to shutdown pid :
            'cat /Users/huangqingshi/app.pid | xargs kill' */
        SpringApplication application = new SpringApplication(ShutdowndemoApplication.class);
        application.addListeners(new ApplicationPidFileWriter("/Users/huangqingshi/app.pid"));
        application.run();Copy the code

Methods four

The fourth method, which also exits the program by calling a springApplication.exit () method, generates an exit code that can be passed to all contexts. This is a JVM hook, and calling this method will execute and stop all PreDestroy methods and pass specific exit codes to all contexts. This error code can also be passed to the JVM by calling System.exit(exitCode). Process finished with exit code 0 gives the JVM a SIGNAL.

          /* method 4: exit this application using static method */
ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.class, args);
exitApplication(ctx);Copy the code

public static void exitApplication(ConfigurableApplicationContext context) {
        int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);

        System.exit(exitCode);
}Copy the code

Methods five

The fifth method is to write a Controller, and then get the Controller written by yourself into the program context, and then call the Controller method configured by yourself to exit the program. Close the program by calling the /shutDownContext method you wrote yourself:

The curl -x POST at http://localhost:3333/shutDownContext.

package com.hqs.springboot.shutdowndemo.controller; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; /** * @author huangqingshi * @Date 2019-08-17 */ @RestController public class ShutDownController implements ApplicationContextAware { private ApplicationContext context; @PostMapping("/shutDownContext") public String shutDownContext() { ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) context; ctx.close(); return "context is shutdown"; } @GetMapping("/") public String getIndex() { return "OK"; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; }}Copy the code

Ok, Springboot’s elegant shutdown method is also implemented, and some students ask, how does the violence stop? Simple: Kill the corresponding PID of -9.

conclusion

The above methods are relatively simple to achieve, but there are still many points to consider in real work, such as the need to protect exposed points from being used by others, generally add some firewalls, or only use in the Intranet, to ensure the security of the program.

In real work, the third method is more commonly used. It is better to gracefully shut down programs that use memory queues or thread pools, save the memory queues that are not processed, or finish processing the programs that are not processed in the thread pools. However, because downtime is relatively quick, it is best not to process a large number of data operations when the service is stopped, which will affect the program to stop.

Ok, if you haven’t seen all of them, you can visit my GIT code:

https://github.com/stonehqs/shutdowndemo.git.Copy the code

Welcome to pay attention to my public number: : a little tutorial. Get exclusive organized learning resources and daily dry goods push.

If you are interested in my series of tutorials, you can also check out my website: yiidian.com