当你在 IntelliJ IDEA 中启动一个 Spring Boot 项目并点击“Stop”按钮后,IDEA 会执行一系列操作来停止应用程序。以下是详细的步骤和说明:
1. 发送停止信号
当你点击“Stop”按钮时,IntelliJ IDEA 会向正在运行的 Spring Boot 应用程序发送一个停止信号。这个信号通常是通过操作系统的进程管理机制发送的,例如发送一个 SIGTERM
信号(在 Unix-like 系统上)。
2. 应用程序处理停止信号
Spring Boot 应用程序接收到停止信号后,会开始执行关闭流程。这包括以下几个步骤:
2.1. 触发 ApplicationEvent
Spring Boot 会触发一系列的 ApplicationEvent
,通知各个组件和监听器应用程序即将关闭。主要的事件包括:
ContextClosedEvent
:ApplicationContext 被关闭。ContextStoppedEvent
:ApplicationContext 被停止。
2.2. 关闭连接池
如果应用程序使用了连接池(如 HikariCP、C3P0、Druid 等),连接池会关闭所有已建立的数据库连接,并释放相关资源。
2.3. 关闭定时任务
如果有定时任务(如使用 @Scheduled
注解的任务),这些任务会被取消,并且相关的调度器会被关闭。
2.4. 关闭 WebSocket 连接
如果有 WebSocket 连接,这些连接会被关闭。
2.5. 关闭 HTTP 服务器
如果应用程序使用了嵌入式 HTTP 服务器(如 Tomcat、Jetty、Undertow 等),HTTP 服务器会被关闭,停止监听端口。
2.6. 执行 @PreDestroy
方法
如果某些 Bean 定义了 @PreDestroy
方法,这些方法会在 Bean 销毁之前被调用,用于执行清理工作。
3. 释放资源
应用程序会释放所有占用的资源,包括但不限于:
- 文件句柄
- 网络连接
- 内存资源
4. 终止 JVM 进程
当所有资源都被释放并且所有关闭操作完成后,Java 虚拟机(JVM)进程会被终止。
5. 日志记录
在整个关闭过程中,Spring Boot 会记录日志,帮助你了解关闭过程中的详细信息。这些日志可以帮助你调试和排查问题。
示例代码
以下是一个简单的 Spring Boot 应用程序,展示了如何在关闭时执行一些清理操作:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
@Configuration
public class ShutdownConfiguration {
@Autowired
private MyService myService;
@Bean
public CommandLineRunner commandLineRunner() {
return args -> {
// 启动时的初始化操作
System.out.println("Application started");
myService.init();
};
}
@EventListener(ContextClosedEvent.class)
public void onApplicationEvent(ContextClosedEvent event) {
// 应用程序关闭时的清理操作
System.out.println("Application is shutting down");
myService.cleanup();
}
}
@Service
public class MyService {
public void init() {
// 初始化操作
System.out.println("MyService initialized");
}
public void cleanup() {
// 清理操作
System.out.println("MyService cleaned up");
}
}
注意事项
-
优雅关闭:
- 确保应用程序能够在接收到停止信号后优雅地关闭,避免数据丢失或资源泄露。
- 你可以通过增加
server.shutdown
属性来配置优雅关闭的时间,例如:server: shutdown: graceful shutdown-timeout: 30s
-
日志记录:
- 在关闭过程中记录日志,帮助你了解关闭过程中的详细信息。
-
外部资源:
- 如果应用程序使用了外部资源(如文件、网络连接等),确保在关闭时正确释放这些资源。
通过以上步骤,你可以确保在 IntelliJ IDEA 中停止 Spring Boot 项目时,应用程序能够安全、优雅地关闭。
============================================================================================================================================================================================================================================================================================================================================
当你的 Spring Boot 应用程序运行在 Docker 容器中时,重新构建并删除原先的容器涉及的步骤与手动关闭应用程序有所不同。以下是如何在 Docker 容器中处理这些操作的详细说明:
1. 手动关闭应用程序(非 Docker 环境)
当你在非 Docker 环境中手动关闭 Spring Boot 应用程序时,IntelliJ IDEA 会发送一个停止信号(如 SIGTERM
),应用程序会执行关闭流程,包括关闭连接池、定时任务、HTTP 服务器等。
2. 在 Docker 容器中重新构建和删除容器
2.1. 构建新的 Docker 镜像
首先,你需要构建新的 Docker 镜像。假设你的 Dockerfile 如下:
FROM openjdk:11-jre-slim
COPY target/myapp.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
构建新的镜像:
docker build -t myapp:latest .
2.2. 停止并删除旧的容器
-
查找旧的容器:
docker ps -a
这将列出所有正在运行和已停止的容器。找到你的旧容器的容器 ID 或名称。
-
停止旧的容器:
docker stop <container_id_or_name>
这将向容器发送一个
SIGTERM
信号,容器内的应用程序会执行关闭流程。 -
删除旧的容器:
docker rm <container_id_or_name>
这将删除已停止的容器。
2.3. 启动新的容器
启动新的容器:
docker run -d --name myapp -p 8080:8080 myapp:latest
3. 对比手动关闭操作
3.1. 停止信号
- 手动关闭:IntelliJ IDEA 发送
SIGTERM
信号,应用程序执行关闭流程。 - Docker 停止:
docker stop
命令发送SIGTERM
信号,容器内的应用程序执行关闭流程。如果应用程序在指定时间内没有关闭,Docker 会发送SIGKILL
信号强制终止容器。
3.2. 资源释放
- 手动关闭:应用程序负责释放所有资源,包括数据库连接、文件句柄、网络连接等。
- Docker 停止:容器停止后,Docker 会自动释放容器占用的资源,如网络端口、文件系统等。应用程序内部的资源释放仍然由应用程序本身负责。
3.3. 容器管理
- 手动关闭:应用程序关闭后,JVM 进程终止,操作系统释放资源。
- Docker 停止和删除:容器停止后,Docker 会保留容器的元数据(除非使用
docker rm
删除)。删除容器后,Docker 会彻底移除容器及其相关资源。
4. 优雅关闭
为了确保在 Docker 环境中优雅关闭应用程序,可以在 Dockerfile 中添加一个健康检查脚本,并在应用程序中处理 SIGTERM
信号。
4.1. 健康检查脚本
在 Dockerfile 中添加健康检查:
FROM openjdk:11-jre-slim
COPY target/myapp.jar /app.jar
COPY healthcheck.sh /healthcheck.sh
RUN chmod +x /healthcheck.sh
HEALTHCHECK CMD /healthcheck.sh
ENTRYPOINT ["java", "-jar", "/app.jar"]
healthcheck.sh
脚本示例:
#!/bin/sh
curl --fail http://localhost:8080/actuator/health || exit 1
4.2. 处理 SIGTERM
信号
在 Spring Boot 应用程序中处理 SIGTERM
信号:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
@org.springframework.context.annotation.Bean
public ApplicationListener<ContextClosedEvent> contextClosedEventListener() {
return event -> {
System.out.println("Application is shutting down");
// 执行清理操作
cleanup();
};
}
private void cleanup() {
// 清理操作
System.out.println("Cleanup completed");
}
}
总结
- 手动关闭:通过 IDE 发送停止信号,应用程序执行关闭流程。
- Docker 停止和删除:通过
docker stop
发送停止信号,容器内的应用程序执行关闭流程,Docker 释放资源并删除容器。
通过上述步骤,你可以确保在 Docker 环境中优雅地停止和删除容器,并启动新的容器。这有助于保持系统的稳定性和资源的有效管理。