项目【myWeb】
【pom.xml】
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
【application.properties】
bash
server.port=8080
spring.application.name=myWeb
【MyWebTest.java】
java
package com.chz.myWeb;
@SpringBootApplication()
public class MyWebTest {
public static void main(String[] args) {
registerHook();
SpringApplication.run(MyWebTest.class, args);
}
private static void registerHook() {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// 当pod关闭的时候会触发这个回调
System.out.println(LocalDateTime.now() + "-->Hook.run 1....");
// 关闭spring boot
ShutdownHelper.shutdown();
System.out.println(LocalDateTime.now() + "-->Hook.run 2....");
}));
}
}
【TestController.java】
java
package com.chz.myWeb.controller;
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
// 当【applicationContext.close()】被调用的时候这些destroy方法会被调用
@PreDestroy
private void destroyBean()
{
System.out.println("TestController::destroyBean start");
try {
// 如果某个队列里面有很多的数据,我们可以在这里调用队列的方法让线程阻塞至队列数据被全部发出去。
Thread.sleep(10000L);
} catch (InterruptedException e) {
}
System.out.println("TestController::destroyBean end");
}
@GetMapping("/shutdown")
public String shutdown() {
// 这里直接调用关闭
ShutdownHelper.shutdown();
return "shutdown";
}
}
【ShutdownHelper.java】
java
package com.chz.myWeb.helper;
@Component
public class ShutdownHelper implements ApplicationContextAware {
@Autowired
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static void shutdown() {
new Thread(()->{
if( applicationContext instanceof ConfigurableApplicationContext){
// 这里调用了applicationContext.close之后spring boot的接口就不会再接收请求了
((ConfigurableApplicationContext) applicationContext).close();
}
}).start();
}
}
【ThreadTestComponent.java】
java
package com.chz.myWeb.helper;
@Component
public class ThreadTestComponent {
private static Thread testThread = null;
@PostConstruct
private void init()
{
testThread = new Thread(()->{
while(true){
try {
System.out.println("ThreadTestComponent::startTestThread()");
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
break;
}
}
});
testThread.start();
}
@PreDestroy
private void destroy()
{
System.out.println("ThreadTestComponent::destroy()");
// 这种自己创建的线程在【application.close()】被调用时是不会自动关闭的,需要手动关闭。
testThread.interrupt();
}
}
试调用一下【http://localhost:8080/test/shutdown】
说明调用【applicationContext.close()】确定可以优雅关闭spring boot程序。
不过线上我们肯定不会去调用这样一个接口,线上pod在关闭的时候会调用【ShutdownHook】,然后在那里调用【applicationContext.close()】就可以了。