Routing Slip – 동적 라우팅 슬립
Routing Slip 패턴은 메시지가 통과해야 할 처리 단계 목록을 미리 메시지에 첨부하는 방식입니다. 메시지가 라우트를 따라 이동하면서 슬립에 적힌 순서대로 처리됩니다.
Routing Slip 구현
// 헤더에 라우팅 슬립 지정
from("direct:orderEntry")
// 헤더에 처리 단계를 콤마로 구분해 저장
.setHeader("routingSlip",
simple("direct:validate,direct:inventory,direct:billing,direct:ship"))
.routingSlip(header("routingSlip"))
.log("모든 단계 처리 완료");
// 또는 Bean으로 동적 결정
from("direct:processOrder")
.bean(OrderRouter.class, "buildRoutingSlip")
.routingSlip(body()); // body에서 라우팅 슬립 읽기
@Component
public class OrderRouter {
public String buildRoutingSlip(@Body Order order) {
StringBuilder slip = new StringBuilder("direct:validate");
if (order.isHighValue()) slip.append(",direct:fraudCheck");
if (order.isInternational()) slip.append(",direct:customs");
slip.append(",direct:fulfillment");
return slip.toString();
}
}
@RoutingSlip 어노테이션
@Component
public class AnnotatedRouter {
@RoutingSlip(delimiter = ",")
public String route(@Header("orderType") String type) {
return switch (type) {
case "DIGITAL" -> "direct:digital,direct:emailDelivery";
case "PHYSICAL" -> "direct:physical,direct:warehouse,direct:shipping";
default -> "direct:unknown";
};
}
}
from("direct:order")
.bean(AnnotatedRouter.class);
Dynamic Router – 단계별 동적 결정
각 단계를 처리한 후 다음 목적지를 동적으로 결정하는 패턴입니다. null을 반환하면 라우팅이 종료됩니다.
@Component
public class DynamicOrderRouter {
private final Map<String, String> stateMap = new ConcurrentHashMap<>();
@DynamicRouter
public String route(Exchange exchange, @ExchangeProperty("currentState") String state) {
String orderId = exchange.getIn().getHeader("orderId", String.class);
if (state == null) {
exchange.setProperty("currentState", "VALIDATE");
return "direct:validateOrder";
}
return switch (state) {
case "VALIDATE" -> {
exchange.setProperty("currentState", "INVENTORY");
yield "direct:checkInventory";
}
case "INVENTORY" -> {
exchange.setProperty("currentState", "PAYMENT");
yield "direct:processPayment";
}
case "PAYMENT" -> null; // 라우팅 종료
default -> null;
};
}
}
from("direct:order")
.dynamicRouter(method(DynamicOrderRouter.class, "route"));
Load Balancer EIP – 부하 분산
여러 처리 인스턴스 또는 서버에 부하를 분산합니다.
// 라운드 로빈 (균등 분배)
from("direct:orders")
.loadBalance().roundRobin()
.to("direct:server1", "direct:server2", "direct:server3")
.end();
// 랜덤 분배
from("direct:orders")
.loadBalance().random()
.to("direct:worker1", "direct:worker2")
.end();
// Sticky (같은 키는 같은 서버로)
from("direct:orders")
.loadBalance()
.sticky(header("customerId"))
.to("direct:node1", "direct:node2")
.end();
// 가중치 기반
from("direct:orders")
.loadBalance()
.weighted(true, "3,1,1") // 60%, 20%, 20%
.to("direct:heavy", "direct:medium", "direct:light")
.end();
Failover Load Balancer
// 실패 시 다음 서버로 자동 전환
from("direct:orders")
.loadBalance()
.failover(3, false, true, // 최대 3번, 라운드로빈, inheritErrorHandler
IOException.class, TimeoutException.class)
.to("http://primary-service/api", "http://secondary-service/api")
.end();