Lifecycle và Phạm vi của Bean trong Spring

Lifecycle của một Bean trong Spring bao gồm quá trình từ việc khởi tạo đến khi bị hủy. Hiểu rõ lifecycle này giúp chúng ta sử dụng đúng cách framework Spring và thực thi các logic tùy chỉnh tại thời điểm thích hợp.

Các giai đoạn chính trong lifecycle của Bean

  • Khởi tạo (Instantiation): Container tạo ra instance của Bean thông qua constructor hoặc factory method.
  • Tiết lập thuộc tính (Populate properties): Thiết lập giá trị cho các thuộc tính và phụ thuộc của Bean.
  • BeanNameAware.setBeanName(): Được gọi nếu Bean triển khai interface này.
  • BeanFactoryAware.setBeanFactory(): Được gọi nếu Bean triển khai interface này.
  • ApplicationContextAware.setApplicationContext(): Được gọi nếu Bean triển khai interface này.
  • BeanPostProcessor.postProcessBeforeInitialization(): Xử lý trước khi initialization.
  • @PostConstruct: Thực hiện phương thức được chú thích với @PostConstruct.
  • InitializingBean.afterPropertiesSet(): Được gọi nếu Bean triển khai interface này.
  • Custom init-method: Thực hiện phương thức khởi tạo tùy chỉnh.
  • BeanPostProcessor.postProcessAfterInitialization(): Xử lý sau khi initialization.
  • Bean sẵn sàng sử dụng.
  • @PreDestroy: Thực hiện phương thức được chú thích với @PreDestroy khi container đóng.
  • DisposableBean.destroy(): Được gọi nếu Bean triển khai interface này.
  • Custom destroy-method: Thực hiện phương thức hủy tùy chỉnh.

Ví dụ về Lifecycle

public class VíDụBean implements BeanNameAware, InitializingBean, DisposableBean {
    private String tên;

    public VíDụBean() {
        System.out.println("1. Khởi tạo Bean");
    }

    public void đặtTên(String tên) {
        System.out.println("2. Thiết lập thuộc tính");
        this.tên = tên;
    }

    @Override
    public void setBeanName(String tên) {
        System.out.println("3. BeanNameAware.setBeanName()");
    }

    @PostConstruct
    public void phươngThứcSauKhiKhởiTạo() {
        System.out.println("5. Phương thức @PostConstruct");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("6. InitializingBean.afterPropertiesSet()");
    }

    public void khởiTạoTuỳChỉnh() {
        System.out.println("7. Custom init-method");
    }

    @PreDestroy
    public void phươngThứcTrướcKhiHủy() {
        System.out.println("9. Phương thức @PreDestroy");
    }

    @Override
    public void destroy() {
        System.out.println("10. DisposableBean.destroy()");
    }

    public void hủyTuỳChỉnh() {
        System.out.println("11. Custom destroy-method");
    }
}

@Configuration
public class CấuHình {
    @Bean(initMethod = "khởiTạoTuỳChỉnh", destroyMethod = "hủyTuỳChỉnh")
    public VíDụBean víDụBean() {
        VíDụBean bean = new VíDụBean();
        bean.đặtTên("Ví dụ Bean");
        return bean;
    }
}

Phạm vi của Bean trong Spring

Spring hỗ trợ nhiều phạm vi khác nhau để tạo ra và quản lý Bean theo nhu cầu cụ thể.

Các phạm vi chuẩn

  • singleton (mặc định): Mỗi định nghĩa Bean chỉ có một instance duy nhất trong mỗi Spring IoC container.
  • prototype: Mỗi yêu cầu tạo ra một instance mới của Bean.
  • request: Mỗi HTTP request tạo ra một instance mới của Bean, chỉ áp dụng cho ứng dụng Web.
  • session: Mỗi HTTP session tạo ra một instance mới của Bean, chỉ áp dụng cho ứng dụng Web.
  • application: Mỗi ServletContext tạo ra một instance mới của Bean.
  • websocket: Mỗi WebSocket session tạo ra một instance mới của Bean, chỉ áp dụng cho ứng dụng WebSocket.

Cấu hình phạm vi

Cách cấu hình bằng XML:

<bean id="dịchVụTàiKhoản" class="com.example.DịchVụTàiKhoản" scope="prototype"/>

Cách cấu hình bằng Annotation:

@Bean
@Scope("prototype")
public DịchVụTàiKhoản dịchVụTàiKhoản() {
    return new DịchVụTàiKhoản();
}

Sử dụng @Scope:

@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class DịchVụPrototype {
    // ...
}

Lời khuyên về việc chọn phạm vi

  • Sử dụng singleton (mặc định) cho các dịch vụ không trạng thái.
  • Sử dụng prototype cho các thành phần có trạng thái.
  • Sử dụng request/session/application dựa trên nhu cầu xử lý dữ liệu Web.
  • Cân nhắc về vấn đề an toàn luồng khi sử dụng prototype.

Tùy chỉnh phạm vi

Spring cho phép đăng ký các phạm vi tùy chỉnh:

public class PhạmViLuồng implements Scope {
    // Thực hiện các phương thức của interface Scope
}

ConfigurableBeanFactory nhàXuất = (ConfigurableBeanFactory) ngữHứngỨngContext.getAutowireCapableBeanFactory();
nhàXuất.registerScope("luồng", new PhạmViLuồng());

@Bean
@Scope("luồng")
public ThànhPhầnCủaTôi thànhPhầnCủaTôi() {
    return new ThànhPhầnCủaTôi();
}

Mối quan hệ giữa Lifecycle và Phạm vi

  • singleton: Được khởi tạo khi container khởi động (ngoại trừ lazy-init), được hủy khi container đóng.
  • prototype: Được khởi tạo mỗi lần yêu cầu, container không theo dõi và không gọi phương thức hủy.
  • request/session: Được khởi tạo khi bắt đầu request/session, được hủy khi kết thúc request/session.

Best Practices

  • Sử dụng singleton (mặc định) trong hầu hết các trường hợp.
  • Cẩn trọng khi sử dụng prototype, chú ý giải phóng tài nguyên.
  • Sử dụng các callback lifecycle một cách hợp lý.
  • Tránh đưa prototype vào singleton, có thể sử dụng method injection để giải quyết.
  • Không đưa các Bean có phạm vi request/session vào singleton.

Thẻ: Spring BeanLifecycle BeanScope

Đăng vào ngày 22 tháng 8 lúc 07:11