쌓고 쌓다

빈 순환 참조 발생 (The dependencies of some of the beans in the application context form a cycle) 본문

프로그래밍/spring

빈 순환 참조 발생 (The dependencies of some of the beans in the application context form a cycle)

승민아 2023. 8. 18. 21:44

일대다 단방향 매핑에서 다대일 양방향 매핑으로 변경하고 이것저것 리팩토링하는 과정에서...

The dependencies of some of the beans in the application context form a cycle 에러가 발생했다.

 

 

예를 들어 설명하자면.

A 클래스 빈을 만드는 과정에서 B 클래스 빈을 주입해야하는 상황이다.

그래서 B 클래스 빈을 만들고자해서 B 클래스 빈을 만드는데 또 이 빈은 만드는데 A 클래스 빈을 주입 받아야하는 상황인것이다.

 

그럼 뭘 먼저 만들어야하는지 알 수 없기에

무한 참조가 일어나는 것이다.

 

그냥 필요할때마다 의존성 주입으로 끌어다 써도 문제 없을줄 알았던 나...

의존성을 잘 설계하는게 중요했었다. 양방향 의존성이라니!!

그러면 다른 서비스를 통해 만들어놓은 로직도 쓰고싶은데 어떻게 사용하라는건가...

 

https://www.baeldung.com/circular-dependencies-in-spring

 

Circular Dependencies in Spring | Baeldung

A quick writeup on dealing with circular dependencies in Spring: how they occur and several ways to work around them.

www.baeldung.com

다양한 해결방법이 있지만 두가지만 사용해보기로 했다.

 

해결 방법 (1)

 

public class PosterService {
    private SpringDataJpaPosterRepository posterRepository;
    private UploadFileService uploadFileService;
    private FileStore fileStore;


    @Autowired
    public PosterService(SpringDataJpaPosterRepository posterRepository, @Lazy UploadFileService uploadFileService, FileStore fileStore) {
        this.posterRepository = posterRepository;
        this.uploadFileService = uploadFileService;
        this.fileStore = fileStore;
    }
}

@Lazy 어노테이션을 사용하여 빈을 Lazy하게 초기화하도록한다.

빈을 완전히 등록하는것이 아닌 프록시를 만들어 주입한다. 이 프록시는 빈이 완전히 필요할때만 생성된다.

 

그래도 설계 자체를 고치는게 올바른 방법인것 같다.

 

해결 방법 (2)

PosterService에서 UploadFileService도 써야하고

UploadFileService에서도 PosterService를 쓰면 좋을텐데...

순환구조를 뜯어고치는 방법이 젤 좋다.

 

@Service
public class UploadFileService {

    public List<UploadFile> findByPno(Long pno) {
        Poster poster = posterService.findByOne(pno).get(); // 문제
        return uploadFileRepository.findByPoster(poster);
    }

}

posterService의 findByOne 메서드를 사용하기위해 posterService를 주입 받으려고 했었다.

사실상 게시글 PK로 게시글을 찾는건 posterRepository로도 가능하기에 아래와 같이 수정했다.

 

@Service
public class UploadFileService {

    private UploadFileRepository uploadFileRepository;
    private SpringDataJpaPosterRepository posterRepository; // 변경된 부분
    private FileStore fileStore;


    @Autowired
    public UploadFileService(UploadFileRepository uploadFileRepository, SpringDataJpaPosterRepository posterRepository, FileStore fileStore) {
        this.uploadFileRepository = uploadFileRepository;
        this.posterRepository = posterRepository; // 변경된 부분
        this.fileStore = fileStore;
    }

    public List<UploadFile> findByPno(Long pno) {
        Poster poster = posterRepository.findById(pno).get(); // 변경된 부분
        return uploadFileRepository.findByPoster(poster);
    }

}

 

 

 

Comments