Đảo Spring Boot
Bờ biển9 phút đọcchặng 1/1

Spring Boot là gì? Từ Spring Framework đến một ứng dụng Java có thể chạy ngay

Spring BootSpring

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 SpringSpring 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:

  1. Auto-configuration
  2. Starter dependencies
  3. Embedded server
  4. Externalized configuration
  5. 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 codeinfrastructure.

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.