Spring Boot là gì? Từ Spring Framework đến một ứng dụng Java có thể chạy ngay
Spring Boot là gì? Từ Spring Framework đến một ứng dụng Java có thể chạy ngay
Nếu đã từng phát triển backend bằng Java, gần như chắc chắn bạn đã nghe đến Spring và Spring Boot.
Spring Framework cung cấp một hệ sinh thái rất lớn để xây dựng ứng dụng Java: Dependency Injection, Web MVC, Transaction, Data Access, Security, Messaging...
Nhưng bản thân Spring Framework không cố gắng làm cho việc khởi tạo một ứng dụng trở nên đơn giản nhất có thể.
Đây chính là nơi Spring Boot xuất hiện.
Spring Boot không phải là một framework hoàn toàn khác với Spring. Nó là một lớp abstraction và convention được xây dựng trên Spring Framework, với mục tiêu chính:
Giảm lượng cấu hình cần thiết để xây dựng và chạy một ứng dụng Spring.
1. Trước Spring Boot, Spring có vấn đề gì?
Để hiểu Spring Boot, trước tiên cần hiểu vấn đề mà nó muốn giải quyết.
Một ứng dụng Spring truyền thống thường cần khá nhiều cấu hình.
Ví dụ, khi xây dựng một web application, developer có thể phải quan tâm đến:
- Cấu hình
ApplicationContext - Cấu hình component scanning
- Cấu hình
DispatcherServlet - Cấu hình DataSource
- Cấu hình transaction
- Cấu hình Jackson
- Cấu hình logging
- Cấu hình server
- Quản lý dependency tương thích với nhau
Các cấu hình này không phải lúc nào cũng khó, nhưng chúng tạo ra rất nhiều boilerplate.
Ví dụ, nếu muốn xây dựng một REST API đơn giản, developer thực sự chỉ muốn viết:
@RestController
public class UserController {
@GetMapping("/users")
public List<User> getUsers() {
return userService.findAll();
}
}
Thay vì phải dành phần lớn thời gian để cấu hình infrastructure.
Spring Boot đưa ra một cách tiếp cận khác:
Convention over Configuration
Nếu application sử dụng một số dependency và cấu hình phổ biến, Spring Boot sẽ tự động thiết lập phần lớn infrastructure cần thiết.
2. Spring Boot thực chất là gì?
Có thể hình dung kiến trúc đơn giản như sau:
Spring Boot
│
┌────────────────┼────────────────┐
│ │ │
Auto Configuration Starters Embedded Server
│ │ │
└────────────────┼────────────────┘
│
Spring Framework
│
┌────────────────┼────────────────┐
│ │ │
IoC MVC Transaction
│ │ │
└────────────────┼────────────────┘
│
JVM
Spring Boot tận dụng những khả năng có sẵn của Spring Framework và bổ sung một số cơ chế quan trọng:
- Auto-configuration
- Starter dependencies
- Embedded server
- Externalized configuration
- Production-ready features
Nhờ đó, developer có thể tập trung nhiều hơn vào business logic thay vì infrastructure configuration.
3. Một ứng dụng Spring Boot tối thiểu
Một ứng dụng Spring Boot có thể bắt đầu từ một class rất đơn giản:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Thoạt nhìn, đoạn code này có vẻ quá đơn giản.
Nhưng bên dưới nó đang kích hoạt khá nhiều cơ chế của Spring.
Đặc biệt là annotation:
@SpringBootApplication
Đây là một annotation tổng hợp từ ba annotation quan trọng:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
Có thể hiểu đơn giản:
@SpringBootApplication
│
├── @SpringBootConfiguration
│
├── @EnableAutoConfiguration
│
└── @ComponentScan
Ba thành phần này đóng những vai trò khác nhau.
4. Component Scan
@ComponentScan cho phép Spring tìm các bean trong application.
Ví dụ:
@Service
public class UserService {
}
và:
@RestController
public class UserController {
}
Spring sẽ scan package của application và phát hiện các class này.
Sau đó chúng được đăng ký vào ApplicationContext.
Có thể hình dung:
Application
│
▼
Component Scan
│
├── UserController
├── UserService
├── UserRepository
└── ...
│
▼
ApplicationContext
Đây chính là nền tảng của Dependency Injection trong Spring.
5. Dependency Injection
Giả sử controller cần UserService:
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
}
Developer không cần tự tạo:
new UserService();
Spring sẽ quản lý object và inject dependency vào constructor.
Đây là một trong những ý tưởng cốt lõi của Spring:
Object không tự quản lý lifecycle và dependency của chính nó. Container sẽ làm việc đó.
Container này chính là:
ApplicationContext
6. Auto-configuration mới là phần quan trọng
Nếu phải chọn một cơ chế đặc trưng nhất của Spring Boot, đó chính là:
Auto Configuration
Ví dụ application có dependency:
spring-boot-starter-web
Spring Boot có thể nhận biết application đang sử dụng web stack và tự động cấu hình những thành phần cần thiết.
Ví dụ:
spring-boot-starter-web
│
▼
Spring MVC
│
▼
DispatcherServlet
│
▼
Embedded Tomcat
Developer không cần tự cấu hình servlet container theo cách truyền thống.
Đây là điểm rất quan trọng:
Spring Boot không "đoán" mọi thứ một cách tùy tiện. Nó sử dụng các điều kiện và configuration metadata để quyết định configuration nào nên được kích hoạt.
Ví dụ, một auto-configuration có thể chỉ được kích hoạt khi một class tồn tại trên classpath:
@ConditionalOnClass(...)
Hoặc chỉ tạo bean khi developer chưa tự định nghĩa bean đó:
@ConditionalOnMissingBean(...)
Do đó, có thể hiểu Auto Configuration là một hệ thống gồm:
Classpath
+
Configuration
+
Conditions
↓
Auto Configuration
↓
Beans
Đây cũng là lý do việc hiểu Spring Boot sẽ dễ hơn rất nhiều nếu đã hiểu Spring IoC Container.
7. Starter là gì?
Một khái niệm khác thường xuyên xuất hiện trong Spring Boot là:
Starter
Ví dụ:
spring-boot-starter-web
spring-boot-starter-data-jpa
spring-boot-starter-security
spring-boot-starter-test
Starter có thể xem như một dependency bundle.
Thay vì phải tự tìm từng dependency:
Spring MVC
Jackson
Validation
Embedded Tomcat
...
Developer chỉ cần:
spring-boot-starter-web
Starter giúp đưa những dependency thường được sử dụng cùng nhau vào project.
Nhưng cần phân biệt:
Starter và Auto Configuration là hai khái niệm khác nhau.
Starter chủ yếu giải quyết vấn đề dependency.
Auto Configuration giải quyết vấn đề configuration.
Có thể hình dung:
Starter
│
▼
Dependencies
│
▼
Classpath
│
▼
Auto Configuration
│
▼
Configured Application
8. Embedded Server
Một đặc điểm rất quan trọng của Spring Boot là khả năng chạy application với embedded server.
Ví dụ với web application, project có thể sử dụng embedded Tomcat.
Thay vì:
Application
│
▼
WAR
│
▼
External Tomcat
Spring Boot hướng tới:
Application
│
▼
Executable JAR
│
├── Application
├── Dependencies
└── Embedded Server
Sau khi build:
java -jar application.jar
application có thể tự khởi động web server.
Đây là một trong những yếu tố khiến Spring Boot đặc biệt phù hợp với cách triển khai hiện đại.
Application trở thành một artifact tương đối độc lập:
JAR → JVM → Application
Thay vì phải quản lý một application server riêng.
9. Configuration bên ngoài application
Spring Boot cũng cung cấp cơ chế externalized configuration.
Ví dụ:
server:
port: 8080
spring:
datasource:
url: jdbc:postgresql://localhost:5432/demo
username: postgres
Application code không cần hard-code những giá trị này.
Có thể thay đổi configuration theo environment:
Development
│
├── application-dev.yml
│
▼
Production
│
├── environment variables
└── external configuration
Điều này đặc biệt quan trọng khi application được deploy qua nhiều environment:
Local
↓
Development
↓
Staging
↓
Production
Code có thể giữ nguyên trong khi configuration thay đổi theo environment.
10. Spring Boot không thay thế Spring Framework
Đây là một hiểu nhầm khá phổ biến.
Spring Boot không phải:
Spring Boot ≠ Spring Framework mới
Mà gần hơn với:
Spring Framework
+
Opinionated defaults
+
Auto Configuration
+
Starter
+
Embedded Server
+
Production features
↓
Spring Boot
Vì vậy khi học Spring Boot, thực chất vẫn đang học Spring.
Các khái niệm như:
- IoC
- Dependency Injection
- Bean
- ApplicationContext
- AOP
- Transaction
- MVC
vẫn là nền tảng.
Spring Boot chủ yếu làm cho việc sử dụng những cơ chế đó trở nên thuận tiện hơn.
11. Tại sao Spring Boot phổ biến trong backend?
Một trong những lý do lớn nhất là nó tạo ra một abstraction khá tốt giữa application code và infrastructure.
Developer có thể tập trung vào:
Business Logic
│
▼
Controller
│
▼
Service
│
▼
Repository
Trong khi Spring Boot xử lý một phần lớn infrastructure:
HTTP Server
Dependency Injection
Configuration
Logging
Serialization
Database Integration
Transaction
Security Integration
Metrics
Health Check
...
Điều này đặc biệt hữu ích khi application trở nên lớn.
Một project thực tế có thể có:
Authentication
Authorization
Database
Cache
Message Broker
REST API
Observability
Transaction
Scheduling
Distributed System
Spring ecosystem cung cấp abstraction cho rất nhiều những thành phần này.
12. Nhưng Spring Boot có phải "magic"?
Không nên xem Spring Boot là magic.
Khi application khởi động:
SpringApplication.run(Application.class, args);
Spring Boot thực hiện một chuỗi hoạt động tương đối phức tạp:
main()
│
▼
SpringApplication
│
▼
Environment
│
▼
ApplicationContext
│
▼
Configuration Classes
│
▼
Auto Configuration
│
▼
Component Scan
│
▼
Bean Registration
│
▼
Dependency Injection
│
▼
Application Ready
Nếu chỉ sử dụng Spring Boot bằng cách copy configuration từ project khác, rất dễ gặp cảm giác:
"Tại sao Spring tự tạo bean này?"
"Tại sao configuration này lại được kích hoạt?"
"Tại sao thêm dependency này thì application thay đổi?"
Để giải quyết những câu hỏi đó, cần đi xuống bên dưới abstraction của Spring Boot.
13. Nên học Spring Boot như thế nào?
Không nên bắt đầu bằng việc học thuộc hàng trăm annotation.
Một hướng tiếp cận tốt hơn là đi theo tầng abstraction:
Java
│
▼
Spring Core
│
├── IoC
├── Dependency Injection
├── Bean
└── ApplicationContext
│
▼
Spring Framework
│
├── Spring MVC
├── Transaction
├── AOP
└── Data Access
│
▼
Spring Boot
│
├── Auto Configuration
├── Starter
├── Embedded Server
└── Externalized Configuration
│
▼
Spring Ecosystem
│
├── Spring Data
├── Spring Security
├── Spring Cloud
└── Spring Integration
Khi hiểu được tầng dưới, những thứ ở tầng trên sẽ không còn giống "magic".
Kết luận
Spring Boot không làm cho Java trở thành một ngôn ngữ khác, cũng không thay thế Spring Framework.
Giá trị lớn nhất của Spring Boot nằm ở việc đưa ra các convention và automation hợp lý trên nền Spring, giúp developer có thể nhanh chóng xây dựng một application hoàn chỉnh mà không phải tự cấu hình mọi infrastructure từ đầu.
Ba khái niệm đặc biệt quan trọng để bắt đầu hiểu Spring Boot là:
Starter
↓
Dependencies
Auto Configuration
↓
Infrastructure
ApplicationContext
↓
Beans + Dependency Injection
Nếu chỉ biết sử dụng:
@SpringBootApplication
thì mới chỉ đang sử dụng Spring Boot.
Còn khi hiểu được vì sao @SpringBootApplication có thể khởi động cả application, Auto Configuration được kích hoạt như thế nào, và Spring tạo và quản lý Bean ra sao, lúc đó mới thực sự bắt đầu hiểu Spring Boot.