Я бы хотел, чтобы вызывающие абоненты передавали внешний маршрутный квитанцию , например, отправив:
POST http://localhost:8080/transform?routing-slip=capitalize&routing-slip=lowercase
Content-Type: text/plain
camelCase
Должна быть возможность использования данного массива маршрутизации в качестве внешней маршрутизации.скольжение из pojo:
@Bean
public IntegrationFlow transformerChain(RoutingSlipRouteStrategy routeStrategy) {
return IntegrationFlows.from(
Http.inboundGateway("/transform")
.headerExpression("routingSlipParam",
"#requestParams['routing-slip']")
.requestPayloadType(String.class))
.enrichHeaders(spec -> spec.header(
IntegrationMessageHeaderAccessor.ROUTING_SLIP,
new RoutingSlipHeaderValueMessageProcessor(
"@routePojo.get(request, reply)")
)
)
.logAndReply();
}
Pojo может получить доступ к заголовку routingSlipParam
, и вы можете подумать, что оно может затем сохранить скольжение как внутреннее состояние, или, по крайней мере, это то, что TestRoutingSlipRoutePojo заставьте меня поверить, поэтому я построил это (с небольшим сомнением, учитывая, что есть только один экземпляр pojo):
public class ExternalRoutingSlipRoutePojo {
private List<String> routingSlip;
private int i = 0;
public String get(Message<?> requestMessage, Object reply) {
if (routingSlip == null) {
routingSlip = (LinkedList)requestMessage.getHeaders()
.get("routingSlipParam");
}
try {
return this.routingSlip.get(i++);
} catch (Exception e) {
return null;
}
}
}
Оказывается, это работает только один раз, что неудивительнов конце концов - индекс увеличивается для каждого входящего сообщения, и квитанция маршрутизации никогда не обновляется.
Поэтому я подумал, конечно, что мне нужно сохранить внутреннее состояние для всех входящих сообщений, и придумал эту RouteStrategy:
public class ExternalRoutingSlipRouteStrategy implements RoutingSlipRouteStrategy {
private Map<UUID, LinkedList<String>> routingSlips = new WeakHashMap<>();
private static final LinkedList EMPTY_ROUTINGSLIP = new LinkedList<>();
@Override
public Object getNextPath(Message<?> requestMessage,Object reply) {
MessageHeaders headers = requestMessage.getHeaders();
UUID id = headers.getId();
if (!routingSlips.containsKey(id)) {
@SuppressWarnings("unchecked")
List<String> routingSlipParam =
headers.get("routingSlipParam", List.class);
if (routingSlipParam != null) {
routingSlips.put(id,
new LinkedList<>(routingSlipParam));
}
}
LinkedList<String> routingSlip = routingSlips.getOrDefault(id,
EMPTY_ROUTINGSLIP);
String nextPath = routingSlip.poll();
if (nextPath == null) {
routingSlips.remove(id);
}
return nextPath;
}
}
Это тоже не работает, потому что стратегия вызывается не только для входящего сообщения, но и для всех новых сообщений, которые создаются dдинамическая маршрутизация, которая, конечно, имеет разные идентификаторы.
Но оно вызывается только дважды для исходного сообщения, поэтому проскальзывание маршрутизации никогда не исчерпывается, и приложение работает в бесконечном цикле.
Как я могу сделать интеграцию пружин с использованием внешней маршрутизациискольжение?
ОБНОВЛЕНИЕ:
Как предположил Гэри Рассел, ни индекс внешней маршрутизации, ни сам внешний маршрут не должны храниться в бине Spring, аможно использовать заголовки сообщений, чтобы поддерживать их отдельно для каждого запроса:
Http.inboundGateway("/transform")
.headerExpression("routingSlipParam",
"#requestParams['routing-slip']")
.requestPayloadType(String.class))
.enrichHeaders(spec -> spec
.headerFunction("counter",h -> new AtomicInteger())
.header(IntegrationMessageHeaderAccessor.ROUTING_SLIP,
new RoutingSlipHeaderValueMessageProcessor(externalRouteStrategy)
)
)
externalRouteStrategy
является экземпляром следующего класса:
public class ExternalRoutingSlipRouteStrategy implements
RoutingSlipRouteStrategy {
@Override
public Object getNextPath(Message<?> requestMessage, Object reply) {
List<String> routingSlip = (List<String>)
requestMessage.getHeaders().get("routingSlipParam");
int routingSlipIndex = requestMessage.getHeaders()
.get("counter", AtomicInteger.class)
.getAndIncrement();
String routingSlipEntry;
if (routingSlip != null
&& routingSlipIndex < routingSlip.size()) {
routingSlipEntry = routingSlip.get(routingSlipIndex);
} else {
routingSlipEntry = null;
}
return routingSlipEntry;
}
}
Для справки, я опубликовал примерв Github .