Spring là framework Java phổ biến nhất, và cũng là thứ bị dùng mà không hiểu nhiều nhất. Bài này bắt đầu bằng câu hỏi cơ bản: nó giải bài toán gì?

Bài toán: nối các mảnh lại với nhau

Một dịch vụ đơn giản cũng có nhiều tầng:

var pool     = new HikariDataSource(cauHinh);
var kho      = new KhoDonHang(pool);
var thanhToan= new CongThanhToan(httpClient, khoaAPI);
var dichVu   = new DichVuDonHang(kho, thanhToan, hangDoiMail);
var handler  = new DonHangController(dichVu);

Với năm lớp thì viết tay được. Với năm mươi lớp — con số bình thường của một dịch vụ thật — bạn có một hàm main dài hàng trăm dòng, và mỗi lần thêm một phụ thuộc là sửa ở nhiều chỗ.

Ba vấn đề nữa xuất hiện: thứ tự khởi tạo, vòng đời (ai đóng pool khi tắt máy), và cấu hình khác nhau giữa môi trường dev, test, sản xuất.

Spring làm việc đó thay bạn. Bạn khai cái gì cần cái gì, Spring dựng đồ thị và tạo theo đúng thứ tự.

Đảo ngược điều khiển

Tên "IoC" nghe hàn lâm nhưng ý rất đơn giản:

Không có Spring: mã của bạn gọi thư viện, và bạn tạo mọi đối tượng.

Có Spring: bạn khai lớp và phụ thuộc, framework tạo đối tượng rồi gọi mã của bạn.

Đó là "đảo ngược" — quyền điều khiển chuyển từ mã của bạn sang container.

@Service
class DichVuDonHang {
    private final KhoDonHang kho;
    DichVuDonHang(KhoDonHang kho) { this.kho = kho; }   // Spring tự truyền vào
}

Không có new KhoDonHang(...) ở đâu cả. Bạn chỉ nói "tôi cần một KhoDonHang".

Cái giá: 266 bean

Tôi dựng một ứng dụng Spring Boot tối giản — chỉ spring-boot-starter-webactuator, ba lớp của riêng tôi:

  tổng số bean: 266
  bean của tôi: [khoPrototype, dichVu, khoSingleton]

Ba bean của tôi, 263 bean của Spring.

Đó là máy chủ Tomcat nhúng, bộ chuyển đổi JSON, xử lý ngoại lệ, quản lý giao dịch, endpoint sức khoẻ, bộ đo chỉ số, và hàng chục thứ khác.

Cùng với nó là thời gian khởi động:

  Started App in 1.146 seconds
  Started App in 1.208 seconds
  Started App in 1.061 seconds

Một giây cho ứng dụng in ra vài dòng. Đặt cạnh sê-ri Go trước đó — một dịch vụ HTTP Go khởi động trong vài mili giây — khác biệt là hai bậc độ lớn.

Và jar:

  fat jar: 22 MB
Đây không phải lý do để chê Spring. 263 bean kia là những thứ bạn sẽ phải tự viết hoặc tự nối: máy chủ HTTP, chuyển đổi JSON, quản lý giao dịch, giám sát. Câu hỏi đúng không phải "nhiều quá không" mà là "tôi có cần chúng không".

Khi nào Spring đáng, khi nào không

Đáng: ứng dụng nghiệp vụ nhiều tầng, đội đông người, cần tích hợp nhiều thứ (CSDL, hàng đợi, bảo mật, giám sát), và vòng đời dự án tính bằng năm.

Không đáng: công cụ dòng lệnh, hàm serverless cần khởi động dưới 100 ms, dịch vụ rất nhỏ chỉ có vài endpoint, hoặc khi khởi động nhanh là yêu cầu cứng.

Với nhóm thứ hai, Go hoặc Java thuần đều hợp lý hơn. Bài 58 của sê-ri này sẽ đo AOT và Native Image — cách Spring thu hẹp khoảng cách đó.

Spring khác Spring Boot

Hai tên hay bị dùng lẫn:

Spring Framework là phần lõi: IoC container, AOP, quản lý giao dịch, Spring MVC. Có từ 2003.

Spring Boot (2014) là lớp bên trên: cấu hình tự động, máy chủ nhúng, starter dependency, và application.yml.

Trước Spring Boot, dựng một ứng dụng Spring nghĩa là hàng trăm dòng XML và một tệp WAR triển khai lên Tomcat riêng. Boot bỏ hết chuyện đó.

Trong sê-ri này, "Spring" gần như luôn nghĩa là Spring Boot.

Ba khái niệm chống đỡ mọi thứ

Ba thứ này sẽ quay lại ở mọi bài sau:

Bean — một đối tượng do container quản lý. Bài 3.

Dependency Injection — cách bean nhận phụ thuộc. Bài 4.

Auto-configuration — cách Boot đoán bạn cần gì từ những jar có trong classpath. Bài 8, và nó là thứ tạo ra 263 bean kia.

Về sê-ri này

Sáu mươi bài, đi từ container tới đưa dịch vụ lên sản xuất. Nguyên tắc giống hai sê-ri trước: không viết điều chưa chạy thử. Mọi con số đều đo trên Spring Boot 3.3 và Java 21, và khi phép đo đi ngược lời khuyên phổ biến, tôi sẽ nói rõ.

Bạn cần Java 21 và Maven. Bài sau sẽ dựng dự án.

Thử ba mươi giây

Nếu bạn đã có một ứng dụng Spring Boot:

System.out.println(ctx.getBeanDefinitionNames().length);

Con số đó là số đối tượng Spring đang quản lý hộ bạn. Với ứng dụng thật, nó thường nằm trong khoảng vài trăm tới hơn một nghìn — và biết con số đó là bước đầu để hiểu chuyện gì xảy ra khi ứng dụng khởi động.

Ngày mai: dựng dự án Spring Boot đầu tiên.