멀티 모듈을 모노 리포지터리로 구성하여 사용하던 중 FeignClient를 사용한 모듈 간 통신 중에 의문이 하나 들었다.
모듈 간 통신하는 과정에서 전달하는 DTO는 형태가 동일한데 이걸 굳이 각 모듈이 필요할 때마다 모듈에 동일한 DTO를 만들어야 할까?
그래서 루트에서 서브 모듈 간 데이터를 공유하기 위한 설정방법을 찾아보게 되었다.
여기서 엄청난 삽질을 하게 되었지만 자주 일어날만한 상황은 아닌지라 가장 마지막 트러블 해결 과정에서 적어보겠다.
갑자기 생각난 공유 배우님의 빡친짤 나도 실패할때마다 딱 저 표정이였다.
프로젝트 구조 확인하기
혼자 실습하는 mas-movie-reservation 프로젝트는 다음과 같은 구조를 지니고 있다.
나는 여기서 movie 모듈과 user모듈을 공유할 것이고, 그 이유는 유저에 대한 정보를 가져오는 과정에서 사용하게 되었다.
영화를 등록하는 api는 admin 이라는 role을 갖고 있는 유저만 수행할 수 있으며, 해당 관리자에 대한 정보를 가져오기 위한 통신이 필요해서 FeignClient로 관리자의 정보를 가져오기로 했다. 이 부분에서는 단순히 userRepository에 쿼리를 날려 가져올 수도 있었지만 그럼 엔티티를 생성해야 하며 User에서 사용하는 엔티티와 Movie에서 사용하는 User에 대한 엔티티에 무결성과 정합성의 일치를 시켜야 하는 번거로움이 생기기 때문에 FeignClient를 통해 유저의 정보를 항상 최신의 정보로 가져오는 것이 더 좋다고 생각했다.
최상위 모듈 설정을 통해 서브 모듈 공유하기
모듈을 공유하는 방법은 두 가지이다.
- 내부에서 모듈간에 데이터를 공유할 수 있도록 인식시키는 방법
- 외부에 라이브러리화시킨 클래스를 배포하고 직접 호출하는 방법
필자는 동현 튜터님에게 위 두가지 방법에 대해 설명을 듣고 외부에 라이브러리화 하는 방법은 복잡하기에 전자를 해보라는 추천을 받았다.
친절하게 설명해주신 튜터님 감사드립니다... <(__)>
1. setting.gradle
최상위 모듈의 setting.gradle에서 서브 모듈을 모두 인식할 수 있도록 설정이 필요하다.
rootProject.name과 include 모듈은 이름이 꼭 일치해야 한다.
참고로 최상위 모듈또한 Gradle기반 애플리케이션이어야 하위 모듈인식이 가능하다. 처음 패키지를 생성할 때 꼭 Spring Initializr 또는 IntelliJ의 프로젝트 생성을 통해 생성하시길... 필자는 여기서 일반 패키지아래 서브 모듈들을 공유시키려 했다가 반나절을 버렸다...
이때 함께 해결을 도와주신 예지 튜터님에게 정말 감사드리며 샤라웃을 해본다...ㅠㅠ
rootProject.name = 'msa-movie-reservation'
include 'movie-reservation-auth'
include 'movie-reservation-gateway'
include 'movie-reservation-server'
include 'movie-reservation-user'
include 'movie_reservation_movie'
2. 모듈 인식 확인
다음과 같이 폴더 아이콘에 마우스를 갖다 대면 모듈이라고 뜨며 아이콘이 변해있다. 이렇게 변했다면 모듈로 인식된 것이다.
movie에서 user서비스를 연결한 상태여서 user에만 모듈로 뜬 것 같다.(이건 내 뇌피셜)
3. 사용할 서비스 모듈에서 가져올 서비스 모듈 연결하는 의존성 연결
movie_reservateion_movie에서 movie-reservation-user의 자원을 사용할 것이기에 movie의 build.gradle에서 다음과 같이 설정해 준다.
implementation project(':movie-reservation-user')
4. 잘 Import 되는지 종속성 연결해 보기
보는 바와 같이 다른 모듈인 movie_reservation_user의 UserResponse를 사용할 수 있었다.
실제로는 이러한 DTO를 공유하기보다는 자주 사용하는 라이브러리 또는 공통으로 설정하는 프레임워크등 중복되는 라이브러리를 하나의 서브 모듈에 넣고 공통적으로 사용하는 데 사용한다.
지금은 모노 리포형식으로 생성하여 모듈 간 공유가 가능하지만 멀티 리포일 경우에는 사용할 수 없는 방식인 걸 참고하도록 하자.
아직 모노리포와 멀티 리포에 대한 개념이 정리되지 않았다면 아래 포스팅도 읽어보는 것을 추천한다.
프로젝트 중 발생했던 문제점
예지 튜터님과 함께 했었던 고난의 과정은 다음과 같았다.
처음 무지성으로 생성한 최상위 패키지를 일반 폴더로 생성했었고 그 이후 모듈 간 데이터 공유의 필요성을 느껴 직접 setting.gradle과 build.gradle을 생성하고 gradle 애플리케이션으로 변경시켰다... 그 이후 아무리 서브 모듈을 인식시키려 해도 되질 않았다
예지 튜터님께서는 인텔리제이의 캐시 문제를 주원인으로 보셨고 IntelliJ의 캐시를 삭제해 보았지만 현상은 동일했다... 그래서 직접 gradle에 들어가 cache 파일을 삭제해 보았으니 오히려 metadata.bin을 찾을 수 없다며 메타 정보를 재 생성하지 못하는 문제가 발생했다.
이에 직접 gradle폴더도 지우고 모든 방법을 동원했으나 결국에는 해결되지 않았고 최상위 모듈을 다시 Spring Initializr를 통해 생성하고 하위 모듈을 넣어줬더니 너무 간단하게 해결되어 버렸다...
이 과정을 통해 인텔리제이에서 이전 정보를 처리하는 캐시를 수동으로 삭제하는 방법을 알게 되었고 다양한 원인 파악을 하게 되어 너무 뜻깊은 경험을 하게 되었다.
'Spring > Spring Cloud' 카테고리의 다른 글
[MSA - Resilienc4j] CircuitBreaker, fallback 메서드 개발하기 (0) | 2025.02.11 |
---|---|
[MSA - Spring Cloud] Spring Cloud Gateway 개발하기 (1) | 2025.02.08 |
[MSA - Spring Cloud] Eureka Client 개발하기(feat. FeignClient) (0) | 2025.02.07 |
[MSA - Spring Cloud] Eureka Server 개발하기(feat. Service Discovery란? 서버/클라이언트 사이드 디스커버리 전략) (0) | 2025.02.07 |
[MSA] 모노 레포와 멀티 레포 전략 (0) | 2025.02.07 |