Bean - Hạt đậu xanh rau má thần kì
Bean trong Spring là gì?
Trong Spring, một đối tượng được tạo ra và được quản lí bởi IoC Container được gọi là Bean.
Đây là một trong những khái niệm quan trọng nhất khi học Spring. Hiểu được Bean là gì, được tạo ra như thế nào và được quản lí ra sao sẽ giúp bạn hiểu sâu hơn về Dependency Injection (DI) và IoC.
1. Bean thực chất là gì?
Hãy bắt đầu từ Java thuần.
Engine engine = new Engine();
Car car = new Car(engine);
Ở đây, chúng ta tự tạo object bằng new.
Khi sử dụng Spring, thay vì tự tạo và quản lí các object, chúng ta có thể giao việc này cho Spring:
@Component
public class Engine {
}
@Component
public class Car {
private final Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
}
Nhìn vào đoạn code trên, một câu hỏi đặt ra là ai sẽ new Car(engine), rồi tham số engine kia ai truyền vào. Câu trả lời là IoC container.Khi Spring khởi động, nó phát hiện Engine và Car, tạo ra các object tương ứng và quản lí chúng trong IoC Container.
Các object đó chính là Bean.
Có thể hình dung:
Spring IoC Container
┌──────────────┐
│ Engine │
│ Bean │
└──────────────┘
┌──────────────┐
│ Car │
│ Bean │
└──────────────┘
2. Bean được tạo như thế nào?
Có nhiều cách để đăng ký Bean với Spring. Phổ biến nhất là sử dụng @Component:
@Component
public class UserService {
}
Spring sẽ scan class này và đăng ký nó vào container.
Ngoài @Component, Spring còn có các annotation chuyên biệt như:
@Service
@Repository
@Controller
@RestController
Về bản chất, các annotation này đều giúp Spring nhận biết class để quản lí. Ví dụ:
@Service
public class UserService {
}
thì UserService có thể trở thành một Bean trong Spring Container.
Một cách khác là sử dụng @Bean:
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
Trong trường hợp này, chính method userService() tạo ra object và Spring lấy object được trả về để quản lí như một Bean.
3. Spring quản lí Bean như thế nào?
Đây mới là phần quan trọng.
Spring không chỉ tạo object rồi bỏ đó. IoC Container quản lí vòng đời của Bean.
Ở mức đơn giản, có thể hình dung:
BeanDefinition
↓
Spring tạo Bean
↓
Inject Dependency
↓
Bean Initialization
↓
Bean được sử dụng
↓
Bean bị destroy
Spring có thể quyết định khi nào Bean được tạo, dependency nào được inject vào Bean và thực hiện những callback cần thiết trong lifecycle.
Ví dụ:
@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
Khi tạo OrderService, Spring thấy constructor yêu cầu PaymentService.
Nếu PaymentService cũng là một Bean:
@Service
public class PaymentService {
}
Spring sẽ lấy PaymentService từ Container và inject vào OrderService.
Đây chính là Dependency Injection.
4. Bean không đồng nghĩa với new
Một hiểu lầm phổ biến là:
"Bean là một object."
Điều này đúng nhưng chưa đầy đủ.
Một object Java bình thường:
UserService service = new UserService();
không tự động trở thành Bean.
Bean là object được IoC Container tạo ra hoặc đăng ký và quản lí.
Ví dụ:
UserService service = new UserService();
Object này nằm ngoài sự quản lí của Spring.
Trong khi:
@Bean
public UserService userService() {
return new UserService();
}
Object được trả về sẽ được Spring quản lí và trở thành Bean.
Vì vậy, điểm quan trọng không nằm ở việc object được tạo bằng new hay không, mà nằm ở việc object đó có được Spring Container quản lí hay không.
5. Bean thường có Singleton scope
Mặc định, Bean trong Spring có singleton scope.
Ví dụ:
@Service
public class UserService {
}
Nếu nhiều nơi cùng inject UserService:
@Service
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
}
và:
@Service
public class UserJob {
private final UserService userService;
public UserJob(UserService userService) {
this.userService = userService;
}
}
thì mặc định Spring sẽ sử dụng cùng một instance UserService trong container.
Tất nhiên, Spring cũng hỗ trợ những scope khác như prototype, request, session... tùy trường hợp sử dụng(90% là dùng singleton).
6. Bean liên quan gì đến IoC?
Có thể nối các khái niệm lại với nhau:
IoC
│
│ Spring nắm quyền quản lí object
↓
IoC Container
│
│ quản lí
↓
Bean
│
│ inject vào
↓
Dependency Injection
Ví dụ:
@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
Bạn không cần viết:
PaymentService paymentService = new PaymentService();
Spring Container chịu trách nhiệm tạo và cung cấp PaymentService.
Đó chính là Inversion of Control: quyền kiểm soát việc tạo và kết nối các dependency được chuyển từ code của chúng ta sang Spring Container.
Kết luận
Bean có thể hiểu đơn giản là:
Một object được Spring IoC Container đăng ký và quản lí.
Bean là nền tảng để Spring thực hiện Dependency Injection, quản lí lifecycle, AOP, transaction và nhiều cơ chế khác.
Khi học sâu hơn về Spring, bạn sẽ gặp các khái niệm như BeanDefinition, BeanFactory, ApplicationContext, BeanPostProcessor...
Đây chính là những thành phần đứng phía sau việc Spring tạo và quản lí Bean.
Nếu muốn hiểu Spring hoạt động bên dưới như thế nào, một hướng học rất tốt là lần theo quá trình:
@Component
↓
Component Scan
↓
BeanDefinition
↓
BeanFactory
↓
Create Bean
↓
Dependency Injection
↓
Bean Lifecycle
Đây cũng là con đường giúp bạn chuyển từ “biết dùng Spring” sang “hiểu Spring hoạt động như thế nào”.