我正在尝试实现从远程系统队列(System.A.out)读取请求消息的Camel路由该路由查看消息正文并动态地将其路由到另一个系统queue(System.B.in)然后该路由完成,并等待其队列中的下一条消息(当前它阻塞并等待临时队列的响应)
System.B读取其队列中的内容(System.B.in,并非始终是驼峰路由)处理消息并在其出队列(System.B.out)系统上删除响应。 B使用请求消息中的JMSMessageID作为其响应上的JMSCorrelationID,即保留该请求的所有内容。
Camel Route(类似于System.A.out,但是监听System.B.out)获取响应消息并使用JMSCorrelationID(请求将没有JMSCorrelationID,因此将通过消息路由body)找到请求的JMSReplyTo队列(System.A.in)并删除System.A队列中的响应,以便System.A进行处理。
我使用的是SpringBoot和Camel 2.18.3,消息队列是IMB MQ版本8
我的路线如下:
@Override
public void configure() throws Exception {
//@formatter:off
Predicate validRoute = header("route-valid").isEqualTo(true);
Predicate inValidRoute = header("route-valid").isEqualTo(false);
Predicate splitRoute = header("route-split").isEqualTo(true);
Predicate singleRoute = header("route-split").isEqualTo(false);
Predicate validSplitRoute = PredicateBuilder.and(validRoute, splitRoute);
Predicate validSingelRoute = PredicateBuilder.and(validRoute, singleRoute);
from(endpoint(incomingURI)).routeId(routeId)
.process(exchange -> {
exchange.getIn().setHeader("route-source", format("%s-%s", incomingURI, routeId));
})
.to(endpoint(format("bean:evaluateIncomingMessageService?method=routeMessage(*, %s)", replyToURI)))
.choice()
.when(validSingelRoute)
.log(DEBUG, "Creating a Single route")
.to(endpoint("bean:messageCoalitionService?method=saveInstruction(*)"))
.setExchangePattern(ExchangePattern.InOut)
.toD("${header.route-recipients}")
.when(inValidRoute)
.log(DEBUG, "a.b.test", format("Incoming message [%s] failed evaluation: %s", incomingURI, body()))
.to(endpoint(deadLetterURI))
.routeId(format("%s-%s", incomingURI, routeId))
.when(validSplitRoute)
.log(DEBUG, "Creating a Split route")
.to(endpoint("bean:messageCoalitionService?method=saveInstructions(*)"))
.setExchangePattern(ExchangePattern.InOut)
.multicast()
.toD("${header.route-recipients}").endChoice()
.otherwise()
.log(DEBUG, "a.b.test", format("Incoming message [%s] failed evaluation: %s", incomingURI, body()))
.to(endpoint(deadLetterURI))
.routeId(format("%s-%s", incomingURI, routeId));
Spring Bean evaluateIncomingMessageService决定消息是请求(无关联ID)还是响应,并为请求设置路由标头。我希望Camel能自动将响应路由到Request.JMSReplyTo队列,如果没有,怎么能这样做呢?
在Camel Route构建器中配置replyToURI,如果路由侦听System.A.out,则其replyToURI将始终为System.A.in。
evaluateIncomingMessageService.routeMessage如下所示:
public void routeMessage(final Exchange exchange, final String replyToURI) {
String correlationId = exchange.getIn().getHeader("JMSCorrelationID", String.class);
if (correlationId != null) {
log.debug("Processing Message Response with JMSCorrelationID [{}]", correlationId);
exchange.getIn().setHeader("JMSReplyTo", replyToURI);
} else {
// Request Messages have nave NO correlationId
log.debug("Processing Message Request with MessageID [{}] and JMSMessageID: [{}]",
exchange.getIn().getMessageId(),
exchange.getIn().getHeader("JMSMessageID") != null ? exchange.getIn().getHeader("JMSMessageID").toString() : exchange.getIn().getMessageId());
String message = exchange.getIn().getBody(String.class);
Set<ContentBasedRoute> validRoutes = contentBasedRouting
.stream().filter(
routeEntity -> Pattern.compile(
routeEntity.getRegularExpression(), DOTALL).matcher(message).matches()).collect(Collectors.toSet());
if (validRoutes.isEmpty()) {
log.warn("No valid routes found for message: [{}] ", message);
exchange.getIn().setHeader("route-valid", false);
} else {
HashMap<String, ContentBasedRoute> uniqueRoutes = new HashMap<>();
validRoutes.stream().forEach(route -> uniqueRoutes.putIfAbsent(route.getDestination(), route));
exchange.getIn().setHeader("route-valid", true);
exchange.getIn().setHeader("route-count", uniqueRoutes.size());
exchange.getIn().setHeader("JMSReplyTo", replyToURI);
//if (exchange.getIn().getHeader("JMSMessageID") == null) {
// exchange.getIn().setHeader("JMSMessageID", exchange.getIn().getMessageId());
//}
if (uniqueRoutes.size() > 1) {
log.debug("Building a split route");
StringBuilder routes = new StringBuilder();
StringBuilder routeIds = new StringBuilder();
StringBuilder routeRegex = new StringBuilder();
uniqueRoutes.keySet().stream().forEach(i -> routes.append(i).append(","));
uniqueRoutes.values().stream().forEach(j -> routeIds.append(j.getRouteId()).append(","));
uniqueRoutes.values().stream().forEach(k -> routeRegex.append(k.getRegularExpression()).append(","));
routes.deleteCharAt(routes.length() - 1);
routeIds.deleteCharAt(routeIds.length() - 1);
routeRegex.deleteCharAt(routeRegex.length() - 1);
exchange.getIn().setHeader("route-split", true);
exchange.getIn().setHeader("route-uuid", routeIds.toString());
exchange.getIn().setHeader("route-regex", routeRegex.toString());
exchange.getIn().setHeader("route-recipients", routes.toString());
} else {
exchange.getIn().setHeader("route-split", false);
exchange.getIn().setHeader("route-uuid", uniqueRoutes.values().iterator().next().getRouteId());
exchange.getIn().setHeader("route-regex", uniqueRoutes.values().iterator().next().getRegularExpression());
exchange.getIn().setHeader("route-recipients", uniqueRoutes.values().iterator().next().getDestination());
}
}
}
}
Bean messageCoalitionService只保存邮件正文和标题,以便可以复制邮件并审核系统。
我不确定我是否错误地解决了这个问题,我应该使用Camel Async API还是需要管道来实现这个?这个模式看起来接近我需要的http://camel.apache.org/async.html(异步请求回复)任何帮助都会非常感谢。
答案 0 :(得分:0)
最后,我使用Spring Integration实现了上述功能。一旦Camel Route发送了消息,我就无法找到检索已发送消息的消息ID的方法,这意味着在发送响应时我无法跟踪关联ID。使用Camel InOut导致Camel阻塞并等待响应,这也不是我想要的。
感谢lutalex提供此解决方案: http://forum.spring.io/forum/other-spring-related/remoting/30397-jmsmessageid-after-message-is-sent?p=745127#post745127