Xử lý lỗi org.springframework.beans.factory.BeanCurrentlyInCreationException trong Java

Trong quá trình phát triển ứng dụng Java sử dụng Spring Framework, một số lỗi liên quan đến Bean có thể xảy ra. Lỗi org.springframework.beans.factory.BeanCurrentlyInCreationException thường xuất hiện khi có sự phụ thuộc vòng (circular dependency) giữa các Bean. Dưới đây là cách hiểu nguyên nhân và phương pháp giải quyết.

Tình huống lỗi

Lỗi này xuất hiện khi Spring đang tạo một Bean nhưng cần phải truy cập vào chính Bean đó trong quá trình khởi tạo. Điều này dẫn đến tình trạng phụ thuộc vòng giữa các Bean. Ví dụ:


package vn.example;

import org.springframework.stereotype.Component;

@Component
class ModuleA {
    private final ModuleB moduleB;

    public ModuleA(ModuleB moduleB) {
        this.moduleB = moduleB;
    }
}

@Component
class ModuleB {
    private final ModuleA moduleA;

    public ModuleB(ModuleA moduleA) {
        this.moduleA = moduleA;
    }
}

Khi chạy ứng dụng, Spring sẽ ném ra ngoại lệ BeanCurrentlyInCreationException vì không thể xử lý được phụ thuộc vòng giữa ModuleA và ModuleB.

Cách khắc phục

1. Sử dụng Setter Injection thay vì Constructor Injection

Thay vì tiêm phụ thuộc qua constructor, bạn có thể sử dụng phương thức setter để gán giá trị sau khi Bean đã được khởi tạo:


package vn.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
class ModuleA {
    private ModuleB moduleB;

    @Autowired
    public void setModuleB(ModuleB moduleB) {
        this.moduleB = moduleB;
    }
}

@Component
class ModuleB {
    private ModuleA moduleA;

    @Autowired
    public void setModuleA(ModuleA moduleA) {
        this.moduleA = moduleA;
    }
}

2. Sử dụng chú thích @Lazy

Bằng cách thêm @Lazy, Spring sẽ trì hoãn việc khởi tạo Bean cho đến khi nó thực sự được sử dụng:


package vn.example;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
class ModuleA {
    private final ModuleB moduleB;

    public ModuleA(@Lazy ModuleB moduleB) {
        this.moduleB = moduleB;
    }
}

@Component
class ModuleB {
    private final ModuleA moduleA;

    public ModuleB(ModuleA moduleA) {
        this.moduleA = moduleA;
    }
}

3. Tạo lớp trung gian

Một cách khác để phá vỡ vòng phụ thuộc là giới thiệu một lớp trung gian:


package vn.example;

import org.springframework.stereotype.Component;

@Component
class SharedResource {}

@Component
class ModuleA {
    private final SharedResource sharedResource;

    public ModuleA(SharedResource sharedResource) {
        this.sharedResource = sharedResource;
    }
}

@Component
class ModuleB {
    private final SharedResource sharedResource;

    public ModuleB(SharedResource sharedResource) {
        this.sharedResource = sharedResource;
    }
}

4. Sử dụng Factory Pattern

Đối với dự án phức tạp, bạn có thể quản lý việc tạo Bean bằng cách sử dụng Factory Pattern:


package vn.example;

public class BeanManager {
    private static final ModuleA moduleA = new ModuleA();
    private static final ModuleB moduleB = new ModuleB();

    static {
        moduleA.setModuleB(moduleB);
        moduleB.setModuleA(moduleA);
    }

    public static ModuleA getModuleA() {
        return moduleA;
    }

    public static ModuleB getModuleB() {
        return moduleB;
    }
}

class ModuleA {
    private ModuleB moduleB;

    public void setModuleB(ModuleB moduleB) {
        this.moduleB = moduleB;
    }
}

class ModuleB {
    private ModuleA moduleA;

    public void setModuleA(ModuleA moduleA) {
        this.moduleA = moduleA;
    }
}

Kiểm tra cấu trúc dự án

Ngoài những cách trên, bạn cũng nên xem xét lại thiết kế của hệ thống để đảm bảo rằng không có các mối liên kết không cần thiết giữa các thành phần. Sử dụng công cụ phân tích phụ thuộc như SonarQube hoặc Dependency-Check có thể giúp xác định vấn đề rõ ràng hơn.

Thẻ: SpringFramework DependencyInjection CircularDependency

Đăng vào ngày 21 tháng 10 lúc 09:15