TIL

9/11

iksadnorth 2023. 9. 11. 22:42

👣 개요

오늘은 10시 부터 Lv 5 과제를 진행했다.
내가 맡은 부분은 좋아요 기능과 예외 처리, 회원 탈퇴 기능이었다.

예외 처리는 단순히 ControllerAdvice를 사용하면 됬고
회원 탈퇴는 단순한 CRUD 중 하나였어서 크게 어렵지는 않았다.

하지만 좋아요 기능은 생각보다 복잡했다.
우선 좋아요를 눌렀던 게시물에 다시 좋아요 API를 호출하면
좋아요 기록이 사라지는 토글 방식이어야 했고
게시글을 조회할 때, 좋아요 총합을 가져와야 했다.

위와 같은 이유로 좋아요 갯수 칼럼을 만드는 것이 아니라
따로 좋아요 테이블을 새로 만들고 좋아요 갯수는 
해당 게시글에 해당하는 좋아요들의 갯수를 계산했다.

문제는 해당 좋아요 갯수를 계산하고
어떤 방식으로 조달받을지에 관한 것이었다.
예를 들어, 기존 게시글 엔티티에는 좋아요 갯수를 위한 칼럼은 없었다.
때문에 @transient 어노테이션을 이용해서 데이터를 전달받을 수 있는
필드를 만들고 @Query를 이용해서 JPQL로 Projection을 적절히 적용하려고 했었다.

하지만 이렇게 된다면 기존에 사용하고 있던 코드들을 대거 수정해야 했고
이는 상당히 에러를 일으킬 위험도 다분했고 시간이 오래 걸리는 작업이었다.

때문에 최근에 '자바 ORM 표준 JPA 프로그래밍'라는 책에서 배운
엔티티 리스너를 이용해서 게시물 혹은 댓글을 DB에서 로드할 때마다
추가로 좋아요 갯수를 조회하는 로직을 @PostLoad로 콜백 함수로 정의했다.

단순히 엔티티 리스너 클래스를 만들어서 적용하면 되겠지라는 
안일한 생각으로 들어갔지만 생각보다 복잡했다.
왜냐 하면 엔티티 리스너는 Bean Container 관리 범위 밖에 존재했기에
LikeService Bean을 받을 수 없었다.

때문에 해당 클래스에 정적 필드를 만들고 
리플렉션으로 직접 ApplicationContext를 주입하려고 했지만
이것은 상당히 복잡한 과정이었기에 단순히
ListenerConfig를 만들고 ApplicationContext 빈이 주입되자 마자
ListenerConfig의 정적 필드에 옮겨 담았다.
그리고 해당 객체로 Listener 내부의 필드를 getBean 메서드로
직접 Bean을 주입했다.

상당히 억지스럽기도 하고 Lazy Initiation을 강제하기 때문에
필드를 final로 제한하기 어려웠다. 최대한 접근 제어자로 제한해서 Setter를 사용하지 못하게
만들었지만 다중 쓰레드가 한꺼번에 몰리게 되면 이미 주입받은 Bean값을 연거푸
주입하는 불상사가 일어날 수도 있는 구조였다. 때문에 Sycronized 제어자도 추가할까 생각했지만
다소 과한 감이 없지 않아 있어서 실제로 적용하진 않았다.

Bean Container 관리 범위 밖의 클래스에
Bean을 주입하는 방법에 대해 좀더 고민해야 겠다는
생각을 하게 된 경험이었다.

 

GitHub - iksadNorth/Level-5-dlwlgns-iksad

Contribute to iksadNorth/Level-5-dlwlgns-iksad development by creating an account on GitHub.

github.com

 

LikesListener.java

https://github.com/iksadNorth/Level-5-dlwlgns-iksad/blob/main/src/main/java/com/sparta/post/listener/LikesListener.java

 

ListenerConfig.java

https://github.com/iksadNorth/Level-5-dlwlgns-iksad/blob/main/src/main/java/com/sparta/post/config/ListenerConfig.java

'TIL' 카테고리의 다른 글

9/13  (0) 2023.09.13
9/12  (0) 2023.09.12
WIL - 9/4 ~ 9/10  (0) 2023.09.10
9/9  (0) 2023.09.09
9/8  (0) 2023.09.08