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();
}
} @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); 각 단계를 처리한 후 다음 목적지를 동적으로 결정하는 패턴입니다. 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")); 여러 처리 인스턴스 또는 서버에 부하를 분산합니다.
// 라운드 로빈 (균등 분배)
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(); // 실패 시 다음 서버로 자동 전환
from("direct:orders")
.loadBalance()
.failover(3, false, true, // 최대 3번, 라운드로빈, inheritErrorHandler
IOException.class, TimeoutException.class)
.to("http://primary-service/api", "http://secondary-service/api")
.end(); 2025년 Apache Camel의 최신 트렌드를 분석합니다. AI/LLM 통합 컴포넌트, 서버리스 배포, Camel K 진화, WebAssembly…
Camel in Action을 완독한 후 Apache Camel의 전체 그림을 다시 정리합니다. 핵심 철학, 학습 경로,…
Apache Camel 2.x에서 3.x, 4.x로 마이그레이션하는 단계별 가이드입니다. 주요 API 변경사항, 제거된 컴포넌트, 자동화 도구…
Apache Camel 라우트에서 발생하는 문제를 디버깅하고 해결하는 실전 기법을 설명합니다. 로그 분석, breakpoint 디버깅, Tracer,…
Apache Camel을 프로젝트에 도입하기 전 알아야 할 핵심 사항을 정리합니다. 학습 곡선, 도입 비용, 적합한…
엔터프라이즈 통합 패턴(EIP) 20가지를 Apache Camel 코드와 함께 한 번에 정리합니다. 메시징 채널, 메시지 라우팅,…