Giải ngố về @SpringBootApplication cách mà một ứng dụng Spring Boot được khởi tạo như thế nào
Làm thế nào Spring Boot khởi động ứng dụng của bạn?
Spring Boot là một trong những framework mạnh mẽ và phổ biến nhất cho việc xây dựng ứng dụng Java hiện đại. Nhưng bạn đã bao giờ tự hỏi điều gì thực sự xảy ra đằng sau dòng lệnh đơn giản SpringApplication.run(Main.class, args);
chưa?
Uki chúng ta đi vào phân tích đoạn code sau để biết một ứng dụng Spring boot khởi tạo như thế nào nhe:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
Vai trò của annotation @SpringBootApplication và các thành phần của nó.
- Cách mà
SpringApplication.run()
thực sự hoạt động. - Quá trình tự động cấu hình (Auto-Configuration) trong Spring Boot.
- Cách ứng dụng quản lý các bean, cấu hình môi trường, và khởi chạy máy chủ web.
1. @SpringBootApplication
Annotation
Thành phần của @SpringBootApplication
:
@SpringBootApplication
là một meta-annotation, bao gồm ba annotation chính:
-
@SpringBootConfiguration
:- Là một alias của
@Configuration
, chỉ định lớp này là lớp cấu hình (configuration class). - Cung cấp khả năng định nghĩa bean trong phương thức với
@Bean
.
- Là một alias của
-
@EnableAutoConfiguration
:- Kích hoạt tính năng Auto-Configuration của Spring Boot:
- Spring Boot tự động cấu hình các bean dựa trên thư viện có trong classpath và cấu hình mặc định.
- Ví dụ:
- Nếu
spring-boot-starter-web
có trong classpath, Spring Boot tự động cấu hình Tomcat và DispatcherServlet. - Nếu có
spring-boot-starter-data-jpa
, Spring Boot cấu hình EntityManager, DataSource, và Hibernate.
- Nếu
- Kích hoạt tính năng Auto-Configuration của Spring Boot:
-
@ComponentScan
:- Kích hoạt cơ chế component scanning:
- Tìm kiếm các bean và component trong package hiện tại và các package con (sub-packages) dựa trên các annotation như
@Component
,@Service
,@Repository
,@Controller
.
- Tìm kiếm các bean và component trong package hiện tại và các package con (sub-packages) dựa trên các annotation như
- Kích hoạt cơ chế component scanning:
- Đây là code mà Spring-boot họ định nghĩa cho interface
SpringBootApplication
:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
2. public static void main(String[] args)
Phương thức main
là điểm bắt đầu (entry point) của ứng dụng Java, và cũng là nơi Spring Boot bắt đầu khởi chạy ứng dụng.
3. SpringApplication.run(Main.class, args)
SpringApplication.run()
là nơi Spring Boot khởi chạy toàn bộ ứng dụng:
-
Tạo đối tượng
SpringApplication
:SpringApplication.run(Main.class, args)
tạo một đối tượngSpringApplication
dựa trên class được truyền vào (ở đây làMain.class
).
Chính xác là như thế này:
@SpringBootApplication public class Main { public static void main(String[] args) { SpringApplication app = new SpringApplication(Main.class); app.run(args); } }
- Xác định loại ứng dụng (WebApplication hoặc CLI Application) dựa trên classpath:
-
Mặc định trong gói
spring-boot-starter-web
bao gồmspring-web
hoặcspring-webmvc
, nó sẽ khởi tạo ứng dụng web. -
Bạn có thể set
WebApplicationType
bằng cách:Có 3 loại WebApplicationType:
NONE | SERVLET | REACTIVE
app.setWebApplicationType(WebApplicationType.SERVLET);
-
-
Cấu hình môi trường (
Environment
):-
Spring tự động load các thông tin từ
application.properties
,application.yml
, hoặc biến môi trường hệ thống. -
Xác định cấu hình active profiles (nếu có).
Active profiles là các nhóm cấu hình xác định cách ứng dụng hoạt động trong các môi trường khác nhau (ví dụ: dev, qa, prod).
Ví dụ trong file build.gradle của bạn có dòng cấu hình sau:
ext { jvmArgs = ['-Dspring.profiles.active=dev'] }
hoặc bạn có thể truyền qua args bằng:
java -jar myapp.jar --spring.profiles.active=dev
Và nếu bạn có file
application-dev.properties
trongResources
thì Spring sẽ load theo thứ tựapplication-dev.properties
đếnapplication.properties
và các thuộc tính trongapplication.properties
(có thể xem như là root config) nó sẽ ghi đè các thuộc tính ở các file config thứ cấp còn lại, trong trường hợp này là:application-dev.properties
-
-
Khởi tạo
ApplicationContext
:- Dựa trên loại ứng dụng, Spring Boot tạo ApplicationContext phù hợp:
- WebApplicationContext: Nếu là ứng dụng web.
- AnnotationConfigApplicationContext: Nếu không phải web.
- ApplicationContext quản lý toàn bộ lifecycle của ứng dụng Spring:
- Tạo, quản lý và khởi tạo các bean.
- Xử lý dependency injection.
- Dựa trên loại ứng dụng, Spring Boot tạo ApplicationContext phù hợp:
-
Tự động cấu hình (Auto-Configuration):
-
Dựa trên
@EnableAutoConfiguration
, Spring Boot tìm kiếm và kích hoạt các cấu hình mặc định trongMETA-INF/spring.factories
. -
Ví dụ khi trong
dependencies
của bạn có góispring-boot-starter-data-jpa
thì ứng dụng sẽ tự động tìm và load các config của datasource nếu bạn không có config thì ứng dụng sẽ bị lỗi và không start được. -
Nếu bạn không muốn tự động cấu hình ví dụ như
data-jpa
thì bạn có thể tắt đi bằng cách sau:
@SpringBootApplication @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) public class Main { public static void main(String[] args) { ... } }
-
-
Kích hoạt Component Scan:
- Dựa trên
@ComponentScan
, tìm kiếm các lớp có annotation như@Component
,@Service
,@Repository
,@Controller
trong package hiện tại và sub-packages.
- Dựa trên
-
Khởi chạy ApplicationContext:
- ApplicationContext khởi tạo tất cả các bean, xử lý injection, và thực hiện các lifecycle callback như:
@PostConstruct
trên bean.- Các listener đăng ký qua
ApplicationListener
.
- ApplicationContext khởi tạo tất cả các bean, xử lý injection, và thực hiện các lifecycle callback như:
-
Kích hoạt các
ApplicationRunner
vàCommandLineRunner
:- Nếu có các bean implement
ApplicationRunner
hoặcCommandLineRunner
, chúng được chạy sau khi ApplicationContext khởi tạo.
- Nếu có các bean implement
-
Khởi chạy máy chủ Web (nếu là ứng dụng web):
- Tự động khởi chạy một máy chủ nhúng hay còn gọi là embedded server (Tomcat, Jetty, hoặc Undertow) để xử lý HTTP request. Mặc định SpringBoot sẽ khởi tạo một Tomcat server, bạn cũng có thể custom lại embedded server này.
- Tạo
DispatcherServlet
để định tuyến các request đến controller tương ứng.
Quá trình khởi động của Spring Boot
Tóm tắt các bước chính khi chạy SpringApplication.run()
:
-
Khởi tạo SpringApplication:
- Xác định loại ứng dụng (web hoặc non-web).
- Chuẩn bị các cấu hình môi trường.
-
Khởi tạo ApplicationContext:
- Tạo ApplicationContext phù hợp.
- Quét và khởi tạo các bean từ
@ComponentScan
.
-
Tự động cấu hình:
- Tải các cấu hình mặc định từ
spring.factories
.
- Tải các cấu hình mặc định từ
-
Khởi chạy ứng dụng:
- Kích hoạt các bean lifecycle.
- Bắt đầu máy chủ web (nếu cần).
Kết luận
Tadaa thì chúng ta đã đi qua cách mà một ứng dụng Spring boot được khởi tạo như thế nào, tuy nó đơn giản nhưng bên dưới, Spring Boot tự động thực hiện nhiều công việc nặng nhọc cho chúng ta như tự động cấu hình, khởi tạo bean, và quản lý lifecycle của ứng dụng.
Các bài tiếp tiếp theo chúng ta sẽ đi sâu chi tiết hơn về các thành phần trên nhé, nếu mn thấy bài viết dễ hiểu thì hãy vote giúp mình để mình có động lực viết thêm nhiều bài viết hay hơn, chất lượng hơn.
Cảm ơn mọi người và hẹn gặp lại mọi người trong các bài viết tiếp theo.
All rights reserved