Spring Là Gì: Bài Toán Framework Giải Quyết Và Bản Đồ Cốt Lõi
Lịch sử Spring từ nỗi đau EJB 2.x, bản chất IoC container, cấu trúc 5 lớp Spring Boot và vòng đời của một HTTP request trong kiến trúc enterprise.
TL;DR: Spring ra đời giai đoạn 2003-2004 nhằm giải quyết sự cồng kềnh, phân tán và khó kiểm thử của Java EE/EJB 2.x. Trọng tâm của framework là giải phóng lập trình viên khỏi việc tự khởi tạo và liên kết các đối tượng bằng toán tử new gây tight coupling, thay bằng cơ chế Inversion of Control (IoC). Spring Boot không phải là một framework thay thế hoàn toàn mới mà là bộ công cụ đóng gói thông minh gồm 5 thành phần: Spring Framework, Starter dependencies, Auto-configuration, Embedded server và Actuator.
Khi mở bất kỳ dự án Java backend quy mô doanh nghiệp nào, bạn đều sẽ bắt gặp tiền tố org.springframework.*. Framework này hiện diện trong phần lớn yêu cầu tuyển dụng kỹ sư Java. Tại sao một nền tảng khởi nguồn từ năm 2003 vẫn giữ vững vị thế áp đảo trong kỷ nguyên microservices hiện nay? Câu trả lời nằm ở tư duy kiến trúc và bài toán đảo ngược quyền điều khiển mà Spring đã giải quyết triệt để.
Vì sao Spring ra đời từ sự thất bại của Java EE và EJB 2.x?
Đầu thập niên 2000, thế giới Java doanh nghiệp chịu sự chi phối của chuẩn Java EE (sau này là Jakarta EE) cùng công nghệ EJB 2.x (Enterprise JavaBeans), chạy trên các Application Server cồng kềnh như BEA WebLogic, IBM WebSphere hay JBoss.
Để hiện thực hóa một logic nghiệp vụ đơn giản như lưu đơn mượn sách (BookingService), nhà phát triển buộc phải tạo tối thiểu 5 thành phần:
- Remote Interface (
BookingServiceRemoteextendsEJBObject): Định nghĩa các hàm gọi từ xa qua giao thức RMI. - Home Interface (
BookingServiceHomeextendsEJBHome): Định nghĩa hàm vòng đời tạo beancreate(). - Bean Class (
BookingServiceBeanimplementsSessionBean): Cài đặt hàng loạt callback nặng nề (ejbCreate,ejbActivate,ejbPassivate,ejbRemove). - Deployment Descriptor chuẩn (
ejb-jar.xml): File cấu hình XML dài hàng chục dòng để khai báo bean với container. - Vendor Deployment Descriptor (
weblogic-ejb-jar.xml): File cấu hình XML đặc thù riêng cho từng hãng máy chủ để ánh xạ tên JNDI.
Hậu quả là 70% mã nguồn dự án chỉ phục vụ cho hạ tầng kỹ thuật (plumbing code) thay vì giải quyết bài toán kinh doanh.

Bốn rào cản chí mạng khiến EJB 2.x sụp đổ:
| Vấn đề | Tác động thực tế |
|---|---|
| Vendor lock-in | Đổi server đòi hỏi viết lại toàn bộ file XML descriptor và xử lý lỗi không tương thích |
| Không thể test offline | Chạy 1 unit test buộc phải khởi động WebLogic mất vài phút mỗi lần |
| Boilerplate khổng lồ | Tốn trung bình 5 file và hàng trăm dòng cấu hình cho mỗi method nghiệp vụ |
| Vòng đời phức tạp | Callback kích hoạt và giải phóng bộ nhớ nhập nhằng, cực kỳ khó truy vết lỗi |
Năm 2002, Rod Johnson xuất bản cuốn sách kinh điển "Expert One-on-One J2EE Design and Development". Ông giới thiệu framework thử nghiệm Interface21, chứng minh rằng lập trình với POJO (Plain Old Java Object) kết hợp container tiêm phụ thuộc gọn hơn gấp 10 lần và kiểm thử offline hoàn hảo. Tháng 3 năm 2004, phiên bản Spring 1.0 chính thức phát hành, mở ra "mùa xuân ấm áp sau mùa đông băng giá của J2EE".
Bài toán cốt lõi về quyền điều khiển đối tượng được giải quyết ra sao?
Hãy xem xét một đoạn mã Java kinh điển khi chưa áp dụng framework quản lý phụ thuộc:
public class OrderService {
private PaymentGateway payment = new StripePayment();
private EmailService email = new SmtpEmailService();
private InventoryClient inventory = new HttpInventoryClient("http://inv:8080");
public void placeOrder(Order order) {
inventory.reserve(order.items());
payment.charge(order.total());
email.send(order.customer(), "Order confirmed");
}
}
Dù đoạn mã này biên dịch và chạy được, nó tiềm ẩn các lỗi kiến trúc nghiêm trọng:
- Khớp nối chặt (Tight Coupling):
OrderServicegắn cứng với cài đặt cụ thểStripePayment. Việc chuyển đổi sang cổng thanh toán khác buộc lập trình viên phải sửa đổi mã nguồn service. - Bất khả thi trong Unit Test: Phương thức
placeOrderkhông thể kiểm thử cô lập mà luôn kích hoạt gọi HTTP ra Stripe thật và SMTP thật. - Rò rỉ cấu hình: Địa chỉ mạng
http://inv:8080bị gắn cứng, đòi hỏi biên dịch lại mã nguồn khi chuyển giữa các môi trường kiểm thử và sản xuất. - Trách nhiệm vòng đời bị phân tán: Không có quy chuẩn dọn dẹp kết nối mạng hay hủy đối tượng khi ứng dụng tắt.
Spring giải quyết vấn đề này bằng việc đưa vào IoC Container:
- Đối tượng không tự khởi tạo phụ thuộc mà chỉ khai báo các hợp đồng (Interface).
- Quyền tạo mới, quản lý vòng đời và liên kết (wiring) các đối tượng được chuyển giao hoàn toàn cho Container bên ngoài.
Spring Framework tổ chức các module kiến trúc như thế nào?
Spring Framework không phải là một file jar đơn khối khổng lồ, mà là tập hợp khoảng 20 module chuyên biệt. Tất cả các tính năng cao cấp đều vận hành trên nền tảng của Core Container:

Các nhóm module then chốt trong hệ sinh thái:
- Core Container (
spring-beans,spring-context): Cung cấpBeanFactoryvàApplicationContext, quản lý vòng đời bean và giải quyết đồ thị phụ thuộc. - Data Access (
spring-jdbc,spring-orm,spring-tx): Chuẩn hóa việc truy cập cơ sở dữ liệu, quản lý giao dịch declarative qua@Transactionalvà tích hợp Hibernate/JPA. - Web Stack (
spring-web,spring-webmvc,spring-webflux): Hỗ trợ xây dựng REST API và Web MVC theo mô hình Servlet blocking truyền thống hoặc Reactive non-blocking Streams. - AOP (
spring-aop): Cung cấp cơ chế lập trình hướng khía cạnh để tách biệt các mối quan tâm xuyên suốt (logging, bảo mật, quản lý giao dịch). - Test (
spring-test): Hỗ trợ kiểm thử tích hợp, nạp context và mock servlet environment.
Spring Boot đóng gói 5 thành phần cốt lõi nào cho ứng dụng?
Trước năm 2014, việc khởi tạo một ứng dụng Spring Framework đòi hỏi hàng loạt thao tác thủ công: cấu hình file web.xml, định nghĩa XML context, cài đặt kết nối cơ sở dữ liệu và triển khai file WAR lên Tomcat ngoài.
Ra mắt năm 2014, Spring Boot không thay thế Spring Framework mà đóng gói toàn diện 5 thành phần cốt lõi:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- Spring Framework Core: Giữ nguyên toàn bộ 20 module nền tảng, không làm thay đổi các quy tắc IoC hay AOP.
- Starter Dependencies: Các dependency rỗng trong Maven/Gradle giúp gom cụm thư viện cần thiết theo use case (ví dụ
spring-boot-starter-webtự động kéo Spring MVC, Jackson và Tomcat nhúng). - Auto-Configuration: Cơ chế tự động nhận diện classpath và đăng ký các bean tương ứng nhờ các điều kiện
@ConditionalOnClasshay@ConditionalOnMissingBean. - Embedded Server: Tích hợp sẵn máy chủ Tomcat, Jetty hoặc Undertow vào file JAR thực thi, giúp khởi chạy ứng dụng trực tiếp qua lệnh
java -jar app.jar. - Production-Ready Actuator: Cung cấp sẵn các endpoint giám sát sức khỏe hệ thống (
/actuator/health), metrics và cấu hình mà không cần viết thêm mã nguồn.
Một HTTP request di chuyển qua các lớp kiến trúc như thế nào?
Để hiểu rõ sự phối hợp giữa các module khi nhận một yêu cầu mạng, hãy quan sát hành trình của một HTTP request từ lúc chạm vào socket cho đến khi ghi dữ liệu xuống cơ sở dữ liệu:

- Tomcat Connector: Nhận socket HTTP thô và bàn giao cho luồng xử lý.
- Servlet Filter Chain: Xử lý các tác vụ xuyên suốt như CORS, Logging và xác thực bảo mật (Spring Security). Nếu xác thực thất bại, request trả về HTTP 401 ngay tại đây mà không đi tiếp vào MVC.
- DispatcherServlet: Đóng vai trò Front Controller tiếp nhận request hợp lệ và điều phối.
- HandlerMapping & HandlerInterceptor: Ánh xạ đường dẫn URL đến phương thức controller tương ứng.
- RestController: Bóc tách tham số, chuyển đổi JSON thành DTO và gọi tầng Service.
- Service & Transaction Proxy: Thực thi logic nghiệp vụ và mở transaction DB thông qua proxy của
spring-tx. - Repository (Spring Data JPA) & Driver: Chuyển đổi thao tác thực thể thành câu lệnh SQL và gửi xuống cơ sở dữ liệu.
Nhờ việc phân định rõ từng lớp trách nhiệm, khi gặp lỗi 401 bạn biết cần kiểm tra Security Filter, gặp 404 xem lại HandlerMapping, và khi dữ liệu không lưu đúng cần kiểm tra tầng Transaction hoặc Repository.
Hệ sinh thái Spring qua các phiên bản tiến hóa ra sao?
Spring không ngừng cải tiến để thích nghi với các tiêu chuẩn mới của ngôn ngữ Java:
- Spring 3.0 (2009): Chuyển dịch toàn diện từ cấu hình XML sang chú thích Java (Annotation-based như
@Component,@Autowired). - Spring 4.0 (2013): Hỗ trợ Java 8, giới thiệu Lambda và generics-aware dependency injection.
- Spring 5.0 (2017): Bổ sung ngăn xếp phản ứng Spring WebFlux hỗ trợ non-blocking I/O.
- Spring 6.0 & Boot 3.0 (2022 trở đi): Nâng cấp chuẩn Java baseline lên Java 17 (khuyến nghị Java 21), hỗ trợ GraalVM native image và chuyển toàn bộ namespace từ
javax.*sangjakarta.*.
| Phiên bản Boot | Phiên bản Framework | Java Baseline | Quy ước Namespace |
|---|---|---|---|
| 2.7.x (Legacy) | 5.3.x | Java 8 | javax.* |
| 3.0.x - 3.3.x | 6.0.x - 6.1.x | Java 17 | jakarta.* |
| 3.4.x (Chuẩn khóa học) | 6.2.x | Java 17 (khuyến nghị 21) | jakarta.* |
Vì sao Spring vẫn chiếm ưu thế áp đảo trong phát triển backend?
Dù nhiều framework hiện đại ra đời sau như Quarkus hay Micronaut có tốc độ khởi động nhanh hơn trên lý thuyết, Spring vẫn giữ thị phần áp đảo nhờ 4 yếu tố then chốt:
- Hệ sinh thái toàn diện và ổn định: Tích hợp sẵn sàng với hàng trăm công nghệ lưu trữ, truyền thông điệp (Kafka, RabbitMQ) và đám mây.
- Khả năng kế thừa và cộng đồng khổng lồ: Mọi sự cố kỹ thuật đều có tài liệu hướng dẫn và kinh nghiệm giải quyết phong phú.
- Đột phá với Spring Boot 3.x: Tận dụng Virtual Threads (Java 21) và Coordinated Restore at Checkpoint (CRaC), giúp giảm thiểu khoảng cách về tài nguyên và hiệu năng.
- Hậu thuẫn chuyên nghiệp từ doanh nghiệp: Đội ngũ kỹ sư nòng cốt phát triển toàn thời gian với chu kỳ phát hành ổn định và cam kết hỗ trợ dài hạn (LTS).
Tóm tắt
- EJB 2.x sụp đổ vì cấu trúc phức tạp và ràng buộc nền tảng; Spring giải phóng lập trình viên bằng mô hình POJO và IoC container.
- IoC Container đảo ngược quyền quản lý đối tượng, chuyển trách nhiệm khởi tạo và kết nối phụ thuộc cho framework bên ngoài.
- Spring Boot là tập hợp 5 thành phần hoàn chỉnh được đóng gói sẵn chứ không thay thế Spring Framework nền tảng.
- Request đi qua chuỗi Filter bảo mật trước khi chạm vào DispatcherServlet và tầng Controller/Service.
Tự kiểm tra
- Q1Một lập trình viên nhận định: "Spring Boot là phiên bản thay thế của Spring Framework nên không cần học Spring Framework nữa." Nhận định này có điểm nào chưa chính xác?
- Q2Liệt kê 3 module Spring Framework thường gặp nhất trong một dự án REST API CRUD tiêu chuẩn kèm annotation đặc trưng của từng module?
- Q3Trong 5 thành phần của Spring Boot, thành phần nào giúp chạy ứng dụng bằng lệnh
java -jarmà không cần cài Tomcat rời, và thành phần nào tự tạoEntityManagerFactorykhi có thư viện JPA? - Q4Tại sao Spring Framework 6.0 và Spring Boot 3.0 lại thay đổi các import từ
javax.*sangjakarta.*? - Q5Khi một client gửi request bị từ chối với mã lỗi HTTP 401 Unauthorized, lớp nào trong kiến trúc đã chặn request này và vì sao breakpoint tại Controller không dừng lại?
Bài tiếp theo: Inversion of Control: Bản Chất Đảo Quyền Điều Khiển
Bài này có giúp bạn hiểu bản chất không?
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Tổng Quan Module: Bản Chất Spring, Triết Lý IoC Và DI
Bài tiếpInversion of Control: Đảo Ngược Quyền Kiểm Soát Trong Spring
Lộ trình Junior Java Backend Developer
Chặng 13/21 · Spring IoC, DI & Bean — bài 2/17 của chặng
Thảo luận & góp ý
Hỏi đáp về bài này