+1

Giải Ngố: Inversion of Control (IoC)

Khi mới học lập trình (C, Java Core), chúng ta thường có thói quen "ôm show".Trong hàm main(), bạn quyết định khi nào tạo đối tượng, khi nào gọi hàm, khi nào huỷ đối tượng. Bạn là Vua, code của ta là lính

Nhưng khi bước chân vào thế giới Spring Boot, ta nghe đến Inversion of Control (IoC) - Đảo ngược điều khiển

Nghe có vẻ "nguy hiểm", nhưng thực chất bó chỉ là việc ta .... giao quyền quản lý cho người khác thôi

1. Ví dụ đời thường: Đi xe máy vs Đi taxi

Để hiểu IoC, hãy so sánh việc tự lái xe và đi taxi

Cách truyền thống (Không có IoC) - Tự lái xe

Ta muốn đi từ A đến B

  • Ta phải tự tìm chìa khoá
  • Tự dắt xe, tự nổ máy
  • Tự đạp phanh, vặn ga, tránh ổ gà => Bạn nắm toàn quyền kiểm soát. Nếu ta mệt, xe không chạy

Cách hiện đại (Có IoC) - Đi Taxi (Grab/be)

Ta muốn đi từ A đến B

  • Ta mwor app, đặt xe
  • Tài xế đến đón. Ta leo lên xe ngồi lướt tóp tóp
  • Tài xế lo việc lái, tránh xe , dừng đèn đỏ -> Quyền điều khiển đã bị đảo ngược từ ta sang tài xế. Bạn không cần lo về quy trình vận hành nữa, chỉ quan tâm kết quả

Trong lập trình : Bác tài xế là Framework (Spring Boot)

2. IoC trong Code : sự thay đổi quyền lực

Hãy xem sự khác biệt trong code Java

Cách cũ: Bạn là bá chủ (Developer Control)

Bạn viết code và tự tay quản lý mọi thứ

public class MyApp {
    public static void main(String[] args) {
        // 1. BẠN tự tạo kết nối database
        MySQLConnection db = new MySQLConnection();
        
        // 2. BẠN tự tạo service và đưa db vào
        UserService service = new UserService(db);
        
        // 3. BẠN tự gọi hàm chạy
        service.run();
    }
}

Vấn đề: thực ra chả sai đâu nhưng ta phải nhớ thứ tự tạo (tạo db trước, rồi mới tạo service). Code càng lớn, thì ta lại càng mệt vì pahir quản lý hàng nghìn các object

Cách mới: Spring là "Bá chủ" (Inversion of Control)

Bạn nhường quyền điều khiển cho Spring (cụ thể là IoC Container)

// Bạn chỉ cần đánh dấu: "Ê Spring, đây là Service nha"
@Service 
public class UserService { ... }

// "Ê Spring, đây là Database nha"
@Component
public class MySQLConnection { ... }

// --- Khi chạy ứng dụng ---
// Spring (IoC Container): "Ok, tôi thấy ông cần UserService. 
// Tôi sẽ tự tạo Database trước, rồi tự tạo UserService, rồi tự nối chúng lại."

Ta không còn viết dòng new UserService() nào cả. Spring tự làm hết. Quyền điều khiển luồng khởi tạo đã bị "Đảo ngược" từ tay bạn sang Framework

3. IoC Container - Bộ não của Spring

Spring có 1 bộ máy gọi là IoC Container. Nó có 2 nhiệm vụ

✔ Nhiệm vụ 1: Scan - Tìm ra object nào cần quản lý

Khi project khởi động, SPring đi quét (scan) toàn bộ code. Khi thấy các annotation này

Spring sẽ nói: "Ồ, đây là bean của tao, để tao quản lý"

✔ Nhiệm vụ 2: Tạo object + ghép dependency

Ví dụ ta có code sau

@Service
public class UserService {
    private final UserRepository repo;

    public UserService(UserRepository repo) {
        this.repo = repo;
    }
}

Spring sẽ làm:

  1. Tạo UserRepository trước
  2. Tạo UserService(repo) và bơm inject cái repo vừa tạo vào
  3. Lưu 2 thằng này vào IoC Container
  4. Khi controller cần -> Spring đưa UserService ra dùng, Spring lôi UserService từ trong túi ra đưa luôn

Hành động Spring tự động nhét repo vào UserService chính là Dependency Injection - cách thức để thực hiện tư tưởng IoC

4. Vậy rốt cuộc "đảo ngược " ở đâu

Hãy nhìn vào bảng so sánh quy trình

Trước IoC (Truyền thống) Sau IoC (Spring Boot)
Bạn new Object Spring tạo Object
Bạn new Dependency Spring tạo Dependency
Bạn gắn Dependency vào Object Spring tự bơm vào
Bạn quản lý thứ tự vào Spring tự tính toán thứ tự

Ta chỉ cần "đăng ký" class bằng annotation

Đảo ngược = quyền điều khiển thuộc về Spring thay vì bạn

5. Minh hoạ bằng flow cụ thể

Giả sử mô hình

UserController → UserService → UserRepository → DatabaseConnection

Khi ta bấm nút Start Spring Boot Application, điều gì xảy ra????

  1. Spring scan project: Spring quét toàn bộ project để tìm các class có annotation (@Controller, @Service....)
  2. Khởi tạo Bean: Spring nhận thấy sự phụ thuộc. Nó sẽ tạo từ dưới lên:
    • Tạo DatabaseConnection
    • Tạo UserRepository (và bơm connection vào)
    • Tạo UserService (và bơm repository vào)
    • Tạo UserController (và bơm service vào)
  3. Lưu trữ: Tất cả các object này (gọi là Bean) được lưu sẵn vào IoC Container (Mặc định là Singleton - chỉ tạo 1 lần duy nhất)
  4. Sẵn sang: Ứng dụng khởi động xong
  5. Xử lý Request: Khi có user gọi API (HTTP Request) tới Controller
    • Spring không cần new lại nữa
    • Spring lấy ngay UserController đã tạo sẵn ở bước 2 ra để xử lý
    • Code chạy vèo vèo

Kết luận

Để tóm tắt về IoC trong Spring, hãy nhớ đến câu nói nổi tiếng của các đạo diễn Hollywood khi casting diễn viên:

"Don't call us, we'll call you." (Đừng gọi cho chúng tôi, khi nào cần chúng tôi sẽ tự gọi bạn.)

Trong lập trình cũng vậy: Bạn cứ viết Class đi, đừng lo việc khởi tạo. Khi nào cần, Spring sẽ tự gọi và cung cấp mọi thứ cho bạn.

Happy Coding! 🚀


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí