순환 참조!

콜트·2021년 3월 19일
0

Edit. 앱 개발기

목록 보기
8/11
post-thumbnail

문제상황

Comment에서 CoverLetter를 추가로 조회하려고 서비스단에서 기능을 구현하는 도중, 필요에 따라 생성자에 Bean으로 등록된 클래스를 추가해주었다. 그러자 위 사진과 같이 순환 참조 문제가 발생했다.

이는 CommentProviderCoverLetterProvider가 서로를 참조하고 있기 때문에 발생한 문제였다. 이를 해결하기 위한 방법 중에는 @Lazy 어노테이션을 사용하는 방식도 있지만 스스로 생각하길, '결국 2개의 Bean이 동시에 호출되는 순간이 올텐데...(지금 구현하려는 기능을 이용해야할 때) 그러면 결국엔 문제가 발생하지 않을까?' 라는 결론에 도달했다.

해결

그래서 대신에 Entity의 연관관계를 적극적으로 이용해보기로 했다(사실 곰곰히 생각해보니 CoverLetterComment를 갖고 있다면 CommentCoverLetter의 조회가 필요하지만 그 반대는 필요하지 않다는 생각이 들었다). 그러니까, 순환 참조가 발생한 Bean 사이의 의존관계를 애초에 만들지 않겠다는 것이다.

이게 무슨 말이냐, CoverLetter에는 Comment가 다수 연결되는 관계였는데(1 : N 관계-@OneToMany) 이에 따라 CoverLetterList<Comment>를 필드로 갖고 있다. 따라서 CoverLetter가 갖고있는 Comment에 대한 책임을 CoverLetter에게 위임함으로써 순환 참조를 피할 수 있었다(이게 적절한 대안이었는지는 아직도 잘 모르겠다).

public class CoverLetterProvider {
    ...
    
    public Object doSomething{
        ...    
        CoverLetter coverLetter = coverLetterRepository.findById(coverLetterId);
        Comment comment = coverLetter.process();
        ...
    }
}

public class CoverLetter {
    ...
    @OneToMany(mappedBy = "coverLetter", cascade = CascadeType.ALL)
    private List<Comment> comments;
    
    public Comment process() {
    	this.comments.stream()
        ...
    }
}

public class Comment {
    ...
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "coverLetterId", nullable = false, updatable = false)
    private CoverLetter coverLetter;
    
    ...
}

역할과 책임에 대해서 고민하고 좋은 설계를 해야 한다고 하는 이유를 조금이나마 알 것 같다.


참고자료


profile
개발 블로그이지만 꼭 개발 이야기만 쓰라는 법은 없으니, 그냥 쓰고 싶은 내용이면 뭐든 쓰려고 합니다. 코드는 깃허브에다 작성할 수도 있으니까요.

0개의 댓글