기억을 지배하는 기록

Message Filter와 Router - 동적 라우팅 구현 본문

Spring Integration for Beginners

Message Filter와 Router - 동적 라우팅 구현

Andrew's Akashic Records 2024. 12. 27. 10:50
728x90
2. Spring Integration 주요 컴포넌트 활용
2.1 Message Filter와 Router

Spring Integration for Backend Developers

동적 라우팅 구현

2.1 동적 라우팅이란?

동적 라우팅은 메시지의 Payload, Header, 또는 외부 조건에 따라 메시지를 다른 채널로 유연하게 전달하는 기능을 말합니다. Spring Integration에서 동적 라우팅은 메시지의 속성을 평가하고, 평가 결과에 따라 적합한 채널로 메시지를 전달하는 방식으로 구현됩니다.

 

활용 예시:

  • 우선순위가 높은 메시지를 빠르게 처리하기 위한 채널로 라우팅.
  • 메시지의 타입에 따라 적절한 비즈니스 로직으로 분기.
  • 외부 설정값이나 환경에 따라 동적으로 메시지를 분배.

2.2 Spring Integration의 라우터 컴포넌트

Spring Integration에서 동적 라우팅을 구현하는 주요 컴포넌트:

  1. ExpressionEvaluatingRouter: Spring Expression Language(SpEL)를 사용해 메시지 속성을 평가하여 적합한 채널로 라우팅.
  2. HeaderValueRouter: 메시지 헤더 값을 기준으로 채널을 선택.
  3. RecipientListRouter: 메시지를 동시에 여러 채널로 전달.

2.3 동적 라우팅의 기본 구성

동적 라우팅은 다음 단계로 구성됩니다:

  1. 입력 채널: 메시지가 수신되는 채널.
  2. 라우터: 메시지를 평가하고 적합한 채널을 선택.
  3. 출력 채널: 라우터에 의해 선택된 채널.
  •  

2.4 Route Sample Code & Test Code

전체 실행 흐름

  1. 메시지 입력:
    • 메시지가 inputRouteChannel로 들어옵니다.
    • 메시지의 헤더 값 level에 따라 라우팅이 결정됩니다.
  2. 라우팅:
    • level 값이 "HIGH"이면 highLevelChannel로 전달.
    • level 값이 "LOW"이면 lowLevelChannel로 전달.
    • 값이 없거나 매칭되지 않으면 defaultRouteChannel로 전달.
  3. 메시지 처리:
    • highLevelChannel → highLevelProcessingFlow에서 처리.
    • lowLevelChannel → lowLevelProcessingFlow에서 처리.
    • defaultRouteChannel → defaultRouteFlow에서 처리.

Route 설정

package kr.co.thekeytech.spring.eai.route;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;

@Configuration
public class DynamicRoutingConfig {

    private final Logger logger = LoggerFactory.getLogger(DynamicRoutingConfig.class);

    // 1. 입력 채널
    @Bean
    public MessageChannel inputRouteChannel() {
        return new DirectChannel();
    }

    // 2. 라우팅된 채널들
    @Bean
    public MessageChannel highLevelChannel() {
        return new DirectChannel();
    }

    @Bean
    public MessageChannel lowLevelChannel() {
        return new DirectChannel();
    }

    @Bean
    public MessageChannel defaultRouteChannel() {
        return new DirectChannel();
    }


    // 3. 동적 라우팅 Flow
    @Bean
    public IntegrationFlow routingFlow() {
        return IntegrationFlow.from("inputRouteChannel")
                .route(Message.class, m -> m.getHeaders().getOrDefault("level", "DEFAULT"),
                        m -> m.
                                channelMapping("HIGH", "highLevelChannel")
                                .channelMapping("LOW", "lowLevelChannel")
                                .defaultOutputChannel("defaultRouteChannel"))
                .get();
    }

    @Bean
    public IntegrationFlow highLevelProcessingFlow() {
        return IntegrationFlow.from("highLevelChannel")
                .handle(message -> logger.info("##### Processing High Level: {}", message.getPayload()))
                .get();
    }

    @Bean
    public IntegrationFlow lowLevelProcessingFlow() {
        return IntegrationFlow.from("lowLevelChannel")
                .handle(message -> logger.info("##### Processing Low Level: {}", message.getPayload()))
                .get();
    }

    @Bean
    public IntegrationFlow defaultRouteFlow() {
        return IntegrationFlow.from("defaultRouteChannel")
                .handle(message -> logger.info("##### Processing Default Route: {}", message.getPayload()))
                .get();
    }
}

라우팅 로직:

  • route 메서드를 사용하여 메시지의 헤더 값(level)을 기반으로 채널을 결정합니다.
  • m.getHeaders().getOrDefault("level", "DEFAULT"):
    • 메시지의 level 헤더 값을 읽습니다.
    • 값이 없을 경우 기본값 "DEFAULT"를 반환합니다.
  • channelMapping:
    • level 값이 "HIGH"이면 highLevelChannel로 메시지를 전달.
    • level 값이 "LOW"이면 lowLevelChannel로 메시지를 전달.
  • defaultOutputChannel:
    • 헤더 값이 "HIGH" 또는 "LOW"가 아닌 경우 메시지를 defaultRouteChannel로 전달.

Gateway  코드

package kr.co.thekeytech.spring.eai.route;

import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.messaging.handler.annotation.Header;

@MessagingGateway
public interface RoutingGateway {
    @Gateway(requestChannel = "inputRouteChannel") // inputRouteChannel 명시적으로 지정
    void sendMessage(String message, @Header("level") String level);
}

Test Code

package kr.co.thekeytech.spring.eai.route;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class DynamicRoutingConfigTest {

    @Autowired
    private RoutingGateway routingGateway;

    @Test
    void routingFlow() {

        // 메시지 전송
        routingGateway.sendMessage("Urgent Task", "HIGH");
        routingGateway.sendMessage("Routine Task", "LOW");
        routingGateway.sendMessage("Unknown Task", "PASS");

    }
}

코드의 장점

  1. 유연한 라우팅:
    • 메시지 헤더 값에 따라 동적으로 처리 경로를 결정할 수 있습니다.
    • 새로운 라우팅 로직을 추가하기 쉽습니다.
  2. 구조화된 처리:
    • 각 라우팅 경로에 대해 별도의 처리 플로우를 정의하므로 유지보수가 용이합니다.
  3. 기본값 처리:
    • defaultRouteChannel로 기본 경로를 지정하여 예외 상황을 방지합니다.

728x90
Comments