ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 멀티 모듈에서 @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

    댓글

Designed by Tistory.