Comment
에서 CoverLetter
를 추가로 조회하려고 서비스단에서 기능을 구현하는 도중, 필요에 따라 생성자에 Bean으로 등록된 클래스를 추가해주었다. 그러자 위 사진과 같이 순환 참조 문제가 발생했다.
이는 CommentProvider
와 CoverLetterProvider
가 서로를 참조하고 있기 때문에 발생한 문제였다. 이를 해결하기 위한 방법 중에는 @Lazy
어노테이션을 사용하는 방식도 있지만 스스로 생각하길, '결국 2개의 Bean
이 동시에 호출되는 순간이 올텐데...(지금 구현하려는 기능을 이용해야할 때) 그러면 결국엔 문제가 발생하지 않을까?' 라는 결론에 도달했다.
그래서 대신에 Entity
의 연관관계를 적극적으로 이용해보기로 했다(사실 곰곰히 생각해보니 CoverLetter
에 Comment
를 갖고 있다면 Comment
는 CoverLetter
의 조회가 필요하지만 그 반대는 필요하지 않다는 생각이 들었다). 그러니까, 순환 참조가 발생한 Bean
사이의 의존관계를 애초에 만들지 않겠다는 것이다.
이게 무슨 말이냐, CoverLetter
에는 Comment
가 다수 연결되는 관계였는데(1 : N 관계
-@OneToMany
) 이에 따라 CoverLetter
는 List<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;
...
}
역할과 책임에 대해서 고민하고 좋은 설계를 해야 한다고 하는 이유를 조금이나마 알 것 같다.