Trong Spring Framework, bean là đối tượng được quản lý bởi Spring container. Sẽ rất quan trọng nếu bạn hiểu được vòng đời của Bean, và tận dụng một số phương pháp của Spring cung cấp để tùy chỉnh cách mà nó được tạo ra cũng như bị hủy.
Tổng quan về Spring Bean life cycle
![Spring Bean life cycle - Vòng đời của Bean trong Spring Spring Bean life cycle - Vòng đời của Bean trong Spring](https://phamanhduc.com/wp-content/uploads/2024/06/Untitled-Diagram.drawio-1024x514.png)
Bean sẽ trải qua lần lượt các giai đoạn như trên trong Spring container. Về cơ bản, vòng đời của một bean chia làm 2 phần:
Phần 1: các giai đoạn khác nhau của bean sau khi được khởi tạo cho đến khi nó sẵn sàng được sử dụng
Phần 2: các giai đoạn của bean sau khi tắt Spring Container
Hãy cùng phân tích kĩ hơn ở các phần tiếp theo.
Instantiate
Spring khởi tạo bean bằng cách gọi constructor của nó.
Populate properties
Sau khi khởi tạo, Spring chèn giá trị, tham chiếu đến bean khác (dependency) cho các thuộc tính của bean.
Aware interface
Spring cung cấp một vài Aware Interface cho phép bạn truy cập vào các hoạt động bên trong của Spring. Bean của bạn có thể truy cập được vào Spring context, bean factory bằng cách implement interface của chúng.
BeanNameAware interface
Nếu bean của bạn cần biết ID của nó trong Spring Container. Hãy implement BeanNameAwere
interface và override method setBeanName
. Spring sẽ gọi phương thức setBeanName
và truyền ID của bean đó.
@Component
public class FileManager implements BeanNameAware{;
@Override
public void setBeanName(String name) {
System.out.println(String.format("Bean's name is %s", name));
}
// The ouput will be: Bean's name is fileManager
}
BeanFactoryAware interface
Đậu của bạn có thể cần truy cập đến Bean Factory mà đã tạo ra nó. Chẳng hạn truy cập vào Bean Factory và lấy một tham chiếu đến thằng bean khác.
@Component
public class FileManager implements BeanFactoryAware{;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println(beanFactory.getBean("helloBean")); // the output: com.pad.springbeanlifecycle.HelloBean@308a6984
HelloBean helloBean = (HelloBean) beanFactory.getBean("helloBean");
System.out.println(helloBean.getHello()); // the output: HELLO
}
}
ApplicationContextAware interface
Tương tự như BeanFactoryAware
interface. Nếu bạn cần lấy những thằng bean khác hoặc truy cập vào các tài nguyên. Hãy implement ApplicationContextAware
interface, override callback method setApplicationContext
, nó sẽ được gọi bởi Spring.
@Component
public class FileManager implements BeanFactoryAware{;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
try {
System.out.println(applicationContext.getResource("test.txt").getFile().getAbsolutePath());
// output: E:\Worksapce\Project\Springboot\SpringBeanLifeCycle\target\classes\test.txt
} catch (IOException e) {
e.printStackTrace();
}
HelloBean helloBean = (HelloBean) applicationContext.getBean("helloBean");
System.out.println(helloBean.getHello()); // the output: HELLO
}
}
Bean Post Processor
BeanPostProcessor
là một interface cung cấp bởi Spring, nó cho phép tương tác với bean để tùy chỉnh hành vi hoặc thuộc tính của nó.
BeanPostProcessor
interface bao gồm hai phương thức:
postProcessBeforeInitialization
: Spring sẽ gọi phương thức này sau khi gọi những phương thức của các Aware interface, và trước khi những gọi những phương thức khởi tạo như là: afterSetProperties
của InitializingBean interface, và init-method tùy chỉnh.
postProcessAfterInitialization
: Spring sẽ gọi lại phương thức này sau khi gọi các phương thức khởi tạo bean.
Hãy xem ví dụ sau đây
public class HelloBean {
private String greeting;
public HelloBean(){
}
public HelloBean(String greeting){
this.greeting = greeting;
}
public String sayHello(){
return greeting;
}
public void initMethod(){
System.out.println("CUSTOM INIT METHOD: " + greeting);
}
}
@Configuration
public class BeanConfiguration {
@Bean(initMethod = "initMethod")
public HelloBean helloBean(){
return new HelloBean();
}
}
@Component
public class HelloBeanPostProcessorImpl implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName){
if(bean instanceof HelloBean) {
System.out.println(String.format("Greeting's values of %s is %s", beanName, ((HelloBean) bean).sayHello()));
bean = new HelloBean("This message was set by postProcessBeforeInitialization method");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if(bean instanceof HelloBean){
return new HelloBean("This message was set by postProcessAfterInitialization method");
}
return bean;
}
}
@SpringBootApplication
public class BeanPostProcessorExampleApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfiguration.class, HelloBeanPostProcessorImpl.class);
HelloBean helloBean = (HelloBean) context.getBean("helloBean");
System.out.println("Greeting after all: " + helloBean.sayHello());
}
}
Output của chương trình sẽ lần lượt là:
Greeting's values of helloBean is null
CUSTOM INIT METHOD: This message was set by postProcessBeforeInitialization method
Greeting after all: This message was set by postProcessAfterInitialization method
Ban đầu, Spring khởi tạo HelloBean
bằng constructor không đối số, lúc này giá trị greeting = null
. Sau đó Spring gọi phương thức postProcessBeforeInitialization
, tại đây can thiệt và trả về một bean với thuộc tính greeting = "This message was set by postProcessBeforeInitialization method"
.
Tiếp tục Spring sẽ gọi các method initMethod
và postProcessAfterInitialization
. Bạn hãy tự kiểm tra nhá.
InitializingBean và DisposableBean Interface
Spring cung cấp hai interface InitializingBean
và DisposableBean
cho phép bạn thực hiện các logic khởi tạo hoặc hủy.
InitializingBean
, inteface này định nghĩa một method duy nhất là afterPropertiesSet
. Spring sẽ gọi phương thức này sau khi các thuộc tính của bean được đặt giá trị.
DisposableBean
, inteface này định nghĩa một method duy nhất là destroy
. Spring sẽ gọi phương thức này trong quá trình hủy đậu khi Spring container tắt.
Hãy tạo bean và implement hai interface này
@Component
public class FileManager implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("Destroy: Clear all temporary file");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("After set properties: perform some calculation");
}
}
Output sẽ như sau:
After set properties: perform some calculation
Destroy: Clear all temporary file
Custom init-method và destroy-method
Ngoài cách implement hai interface bên trên để chọc ngoáy vào quá trình khởi tạo hoặc hủy của bean, bạn có thể tạo custom method bằng cách cấu hình cho bean.
Nếu cấu hình bằng file xml, bạn chỉ định custom init-method và destroy-method bằng hai thuộc tính init-method
và destroy-method
của thẻ.
Nếu cấu sử dụng Annotation autoconfiguration trong Spring Boot, chỉ định initMethod
và destroyMethod
trong @Bean
annotation
@Configuration
public class BeanConfiguration {
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public FileManager fileManager(){
return new FileManager();
}
}
@Component
public class FileManager implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("Destroy: Clear all temporary file");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("After set properties: perform some calculation");
}
public void initMethod(){
System.out.println("Custom init-method");
}
public void destroyMethod(){
System.out.println("Custom destroy-method");
}
}
Theo thứ tự các giai đoạn trong vòng đời của bean, output của code bên trên sẽ như sau:
After set properties: perform some calculation
Custom init-method
Destroy: Clear all temporary file
Custom destroy-method
Theo quan điểm cá nhân, sử dụng custom init-method hoặc destroy-method hơn là implement InitializingBean, DisposableBean interface để không bị ràng buộc chặt chẽ vào Spring.
Bạn có thể tìm source code mẫu tại Github.