Spring Bean life cycle – Vòng đời của Bean trong Spring

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

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 postProcessAfterInitialization. Bạn hãy tự kiểm tra nhá.

InitializingBean và DisposableBean Interface

Spring cung cấp hai interface InitializingBean 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-methoddestroy-method của thẻ.

Nếu cấu sử dụng Annotation autoconfiguration trong Spring Boot, chỉ định initMethoddestroyMethod 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.