🚀 Hiểu Về Vòng Đời Ứng Dụng Spring
Khi bạn khởi động một ứng dụng Spring Boot, rất nhiều điều xảy ra phía sau trước khi mã của bạn sẵn sàng phục vụ các yêu cầu. Giống như các bean có vòng đời của chúng, ứng dụng cũng trải qua một chuỗi sự kiện được xác định rõ ràng.
Bằng cách hiểu về Vòng Đời Ứng Dụng Spring, bạn có thể kiểm soát tốt hơn việc khởi tạo, khởi động và tắt ứng dụng một cách nhẹ nhàng.
🔄 Vòng Đời Ứng Dụng Spring (Tổng Quan)
Khi bạn chạy một ứng dụng Spring Boot (ví dụ: thông qua SpringApplication.run()), các giai đoạn sau sẽ xảy ra:
-
Giai đoạn Khởi Tạo
- Tạo một thể hiện
SpringApplication. - Chuẩn bị các listener và initializer cho ứng dụng.
- Tạo một thể hiện
-
Chuẩn Bị Môi Trường
- Tải các thuộc tính cấu hình (từ
.properties,.yml, biến môi trường, tham số dòng lệnh, v.v.). - Kích hoạt các profile (ví dụ:
dev,prod).
- Tải các thuộc tính cấu hình (từ
-
Tạo ApplicationContext
- Tạo ApplicationContext (container IoC).
- Tải các định nghĩa bean nhưng chưa khởi tạo.
-
Làm Mới ApplicationContext
- Khởi tạo các bean, tiêm sự phụ thuộc và kích hoạt các phương thức vòng đời (vòng đời bean mà chúng ta đã thảo luận trước đó).
- Thực thi các bean
CommandLineRunnervàApplicationRunner.
-
Ứng Dụng Sẵn Sàng
- Phát hành sự kiện
ApplicationReadyEvent. - Ứng dụng đã hoàn toàn hoạt động.
- Phát hành sự kiện
-
Giai Đoạn Tắt
- Khi JVM tắt (ví dụ:
CTRL+C, hoặcSIGTERMtrong containers), Spring thực hiện dọn dẹp:- Gọi các phương thức
@PreDestroy/destroy()trên các bean. - Đóng ApplicationContext.
- Phát hành
ContextClosedEvent.
- Gọi các phương thức
- Khi JVM tắt (ví dụ:
📡 Các Hook Trong Vòng Đời Ứng Dụng
Spring cung cấp nhiều cách để hook vào vòng đời này.
1. Sự Kiện Ứng Dụng
Spring phát hành sự kiện tại các giai đoạn khác nhau. Bạn có thể lắng nghe chúng:
java
@Component
public class MyAppEventsListener {
@EventListener(ApplicationStartingEvent.class)
public void onStart() {
System.out.println("🚀 Ứng dụng đang khởi động...");
}
@EventListener(ApplicationReadyEvent.class)
public void onReady() {
System.out.println("✅ Ứng dụng đã sẵn sàng!");
}
@EventListener(ContextClosedEvent.class)
public void onShutdown() {
System.out.println("🛑 Ứng dụng đang tắt...");
}
}
2. CommandLineRunner và ApplicationRunner
Chạy mã ngay sau khi ApplicationContext đã sẵn sàng.
java
@Component
public class StartupRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("🏃 Đang chạy logic khởi động...");
}
}
ApplicationRunner tương tự nhưng cung cấp cho bạn ApplicationArguments thay vì raw String[].
3. SmartLifecycle
Dành cho các bean cần callback start/stop.
java
@Component
public class MyLifecycleBean implements SmartLifecycle {
private boolean running = false;
@Override
public void start() {
System.out.println("▶️ Bean vòng đời tùy chỉnh đã bắt đầu");
running = true;
}
@Override
public void stop() {
System.out.println("⏹ Bean vòng đời tùy chỉnh đã dừng");
running = false;
}
@Override
public boolean isRunning() {
return running;
}
}
4. DisposableBean / PreDestroy
Trong quá trình tắt, Spring đảm bảo các tài nguyên được giải phóng:
java
@Component
public class ShutdownHook {
@PreDestroy
public void cleanup() {
System.out.println("🧹 Dọn dẹp tài nguyên trước khi tắt...");
}
}
📊 Hình Ảnh Minh Họa Vòng Đời Ứng Dụng
[Khởi Tạo SpringApplication]
↓
[Chuẩn Bị Môi Trường]
↓
[Tạo ApplicationContext]
↓
[Khởi Tạo Beans & Làm Mới Context]
↓
[Thực Thi CommandLineRunner / ApplicationRunner]
↓
[Phát Hành ApplicationReadyEvent → Ứng Dụng Đang Chạy]
↓
[Phát Hành ContextClosedEvent → Hook Tắt]
🔎 So Sánh Các Hook Trong Vòng Đời
| Loại Hook | Khi Nó Chạy | Trường Hợp Sử Dụng Thông Dụng |
|---|---|---|
ApplicationStartingEvent |
Tại rất đầu, trước khi tạo context | Thiết lập logging, khởi tạo metrics |
ApplicationReadyEvent |
Sau khi khởi động hoàn tất | Thông báo cho hệ thống bên ngoài, làm nóng cache |
CommandLineRunner / ApplicationRunner |
Sau khi làm mới context, trước khi sẵn sàng | Logic khởi động, hạt giống dữ liệu |
@PreDestroy / DisposableBean |
Trước khi tắt | Giải phóng tài nguyên |
SmartLifecycle |
Bắt đầu/dừng các bean tùy chỉnh | Quản lý tác vụ nền |
📝 Kết Luận
Vòng đời của Ứng Dụng Spring đảm bảo một luồng xử lý mượt mà từ khởi động → hoạt động → tắt.
- Sử dụng Sự Kiện Ứng Dụng để phản ứng với các giai đoạn quan trọng.
- Sử dụng CommandLineRunner hoặc ApplicationRunner cho logic khởi động.
- Sử dụng @PreDestroy hoặc SmartLifecycle để tắt một cách nhẹ nhàng.
Bằng cách kết hợp hook vòng đời bean với vòng đời ứng dụng, bạn có thể xây dựng các ứng dụng mạnh mẽ, dễ đoán và an toàn về tài nguyên.