-
멀티 모듈에서 @ConditionalOnProperty 사용 시 주의사항Back-end 2024. 3. 7. 10:35반응형
개요
멀티 모듈에서 @ConditionalOnProperty 사용 시 주의해야할 사항에 대한 글입니다.
사건의 발단
여러 모듈에서 중복으로 관리되어지는 Configuration 이 있었다.
이것을 하나의 모듈에 모아 관리하려고 했다.
application.properties 옵션을 이용해 @Configuration 내부 빈 들을 주입할지 결정하도록 설계하려했다.
아래와 같이 옵션이 "true" 인 경우만 빈 들을 등록하는 방향으로 시도했다.
kafka.configuration.order=true kafka.configuration.payment=true kafka.configuration.stock=true
예시의 Configuration 이다.
@Configuration @ConditionalOnProperty(value = "kafka.configuration.order", havingValue = "true") public class OrderConsumerConfiguration { @Value("${kafka.server.url}") private String kafkaUrl; .... }
그러나 각 서비스에서 빈을 찾지 못하는 에러가 발생하였다.
그래서 처음엔 다른 모듈의 빈을 불러오지 못하는 것일까? 라는 생각을 하였다.
해결1: scanBasePackage 경로 변경
예상은 완전 빗나갔다.
Bean Scan이 정상적으로 작동하고 있지 않았다.
Payment-Service로 예시를 살펴보자.
Gradle 에서는 kafka-object(공통 Configuration 관리하는 곳) 라는 모듈을 impot 하여 사용할 수 있도록 지정해놨다.
dependencies { implementation project(':outbox-pattern:kafka-object') implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'mysql:mysql-connector-java:8.0.32' implementation 'org.springframework.kafka:spring-kafka' testImplementation 'org.springframework.boot:spring-boot-starter-test' }
그러나 두 서비스 간 Package level 이 다른 것을 볼 수 있다.(com.example vs com.example.paymentservice)
그래서 Payment-Service 는 com.example.paymentservice 를 기준으로 빈 스캔을 하고있었던 것이다.
Kafka-object Package Payment Package 이렇게 첫 번째 문제는 scanBasePackages 옵션을 이용하여 해결하였다.
@SpringBootApplication(scanBasePackages = "com.example")
해결2: scanBasePackage 경로 제약
두 번째 문제가 되는 Order-Service 서비스의 Gradle 이다.
아래 내용을 보면 위 payment-service 와는 다르게 stock-service, payment-service 가 포함되어져 있다.
dependencies { implementation project(':outbox-pattern:kafka-object') implementation project(':outbox-pattern:stock-service') implementation project(':outbox-pattern:payment-service') implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'mysql:mysql-connector-java:8.0.32' implementation 'org.springframework.kafka:spring-kafka' testImplementation 'org.springframework.boot:spring-boot-starter-test' }
아래는 각 서비스의 scanBasePackage 이다.
kafka-object order-service payment-service stock-service com.example com.example.orderservice com.example.paymentservice com.example.stockservice 처음엔 그럼 이전처럼 "com.example" 불러오면 모든 빈 들이 등록될 것 같은데? 라는 생각이 들었다.
그러나 payment-service, stock-service 에 이름이 같은 빈 들이 존재했고 오류가 발생했다.
또한 com.example 경로로 호출 시 필요없는 빈 까지 호출하므로 관리가 어렵게된다.
결국 scanBasePackages 를 제약할 수 밖에 없었다.
@SpringBootApplication(scanBasePackages = { "com.example.consumer", "com.example.producer", "com.example.orderservice" })
고찰
1. 멀티모듈을 설계하면서 package 명에 대해서 항상 신경쓰자.
2. 별도의 모듈에서 빈 들을 끌어와 사용하는 경우 어떤 빈 들이 주입되는지 확인하자.
반응형'Back-end' 카테고리의 다른 글
MSA - Outbox Pattern? Saga Pattern? (0) 2024.03.19 TestCode 의 properties override 에 대하여 (1) 2024.03.08 Kafka Consumer Retry 구현 (1) 2024.02.27 Micrometer custom metric 생성하기 (0) 2024.01.28