在Spring Boot应用程序中,我们通过利用Spring Integration中的RendezvousChannel
来使用请求-响应模式。收到请求后,我们将创建一个唯一命名的通道,并在Spring应用程序上下文中注册它,如下所示:
RendezvousChannel rendezvousChannel = MessageChannels.rendezvous(uniqueId).get();
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) springContext;
SingletonBeanRegistry beanRegistry = configurableApplicationContext.getBeanFactory();
beanRegistry.registerSingleton(uniqueId, rendezvousChannel);
然后,我们将此频道名称添加到请求中,并执行需要花费几秒钟的工作。然后,对该请求的响应到达并被路由到RendezvousChannel
:
@Bean
public IntegrationFlow flow() {
return IntegrationFlows.from(globalChannel)
.route("payload['replyChannel']")
.get();
}
这很好用,我们会根据需要收到对请求的响应。
但是在负载下,当温度很高时。 RendezvousChannels
已创建,路由有时会失败,并显示以下信息:
org.springframework.messaging.MessagingException: failed to resolve channel name 'uniqueId';
nested exception is org.springframework.messaging.core.DestinationResolutionException: failed to look up MessageChannel with name 'uniqueId' in the BeanFactory.;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'uniqueId' available, failedMessage=GenericMessage...
at org.springframework.integration.router.AbstractMappingMessageRouter.resolveChannelForName(AbstractMappingMessageRouter.java:227)
at org.springframework.integration.router.AbstractMappingMessageRouter.addChannelFromString(AbstractMappingMessageRouter.java:258)
at org.springframework.integration.router.AbstractMappingMessageRouter.addToCollection(AbstractMappingMessageRouter.java:282)
at org.springframework.integration.router.AbstractMappingMessageRouter.determineTargetChannels(AbstractMappingMessageRouter.java:186)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:171)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:158)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:132)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:105)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:73)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:445)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:394)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:181)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:160)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:47)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:108)
at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:426)
目前我不确定为什么会这样。有什么想法吗?
答案 0 :(得分:1)
对于请求答复的情况,我们建议使用@MessagingGateway
:https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints-chapter.html#gateway
此代码将TemporaryReplyChannel
实例填充到replyChannel
键下的标头中。在发送到某些外部出站服务之前,您需要在IntegrationFlow
中使用以下内容:
.enrichHeaders(h -> h.headerChannelsToString())
通过这种方式,将提到的TemporaryReplyChannel
存储在某些特定的HeaderChannelRegistry
中:https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-transformation-chapter.html#header-channel-registry
之后,您确实可以根据需要提供一些transform()
来将replyHeader
打包到有效负载中。为此,我们提供了EmbeddedJsonHeadersMessageMapper
之类的东西,可以从提到的transform()
中将其用作普通的POJO使用者。
收到回复时,应确保至少包含必需的replyChannel
属性和实际的回复有效内容。在这种情况下,您可以再次使用EmbeddedJsonHeadersMessageMapper.toMessage()
将嵌入的标头重新映射回MessageHeaders
,或者您需要确保自己进行重新映射。在这种情况下,必须填充replyChannel
标头很重要。最后,您只需要对标准机制进行答复即可从标头将输出发送到replyChannel
。上面提到的HeaderChannelRegistry
将确保将字符串ID解析为实际的TemporaryReplyChannel
实例,同时开头的网关仍将等待该TemporaryReplyChannel
的值。