Spring boot 在Spring应用程序上下文中找不到注册的RendezvousChannel bean

Spring boot 在Spring应用程序上下文中找不到注册的RendezvousChannel bean,spring-boot,spring-integration,Spring Boot,Spring Integration,在Spring引导应用程序中,我们通过利用Spring Integration的RendezvousChannel使用请求-应答模式。当我们收到请求时,我们创建一个唯一命名的通道,并在Spring应用程序上下文中注册它,如下所示: RendezvousChannel rendezvousChannel = MessageChannels.rendezvous(uniqueId).get(); ConfigurableApplicationContext configurableApplicati

在Spring引导应用程序中,我们通过利用Spring Integration的
RendezvousChannel
使用请求-应答模式。当我们收到请求时,我们创建一个唯一命名的通道,并在Spring应用程序上下文中注册它,如下所示:

RendezvousChannel rendezvousChannel = MessageChannels.rendezvous(uniqueId).get();
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) springContext;
SingletonBeanRegistry beanRegistry = configurableApplicationContext.getBeanFactory();
beanRegistry.registerSingleton(uniqueId, rendezvousChannel);
然后,我们将此通道名称添加到请求中,并执行一些耗时数秒的工作。然后,对该请求的响应到达,并被路由到
集合频道

@Bean
public IntegrationFlow flow() {
    return IntegrationFlows.from(globalChannel)
            .route("payload['replyChannel']")
            .get();
}
这非常有效,我们可以根据需要收到对请求的响应。 但在负载下,当大量的温度<创建代码>集合通道,路由有时会失败,原因是:

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)

目前我不确定为什么会发生这种情况。对此有何想法?

对于请求-回复场景,我们建议使用
@MessagingGateway

这一个将
临时replyChannel
实例填充到
replyChannel
键下的头中。在发送到某个出站外部服务之前,您需要在
集成流中使用类似的内容:

.enrichHeaders(h -> h.headerChannelsToString())
这样,所述的
临时回复频道
存储在某个特定的
标题频道注册表中

之后,您确实可以提供一些
transform()
来根据您的需求将
replyHeader
打包到有效负载中。为此,顺便提一下,我们提供了类似于
EmbeddedJsonHeadersMessageMapper
的东西,它可以从前面提到的
transform()
作为普通POJO使用者使用


当您收到回复时,应确保至少required
replyChannel
属性与实际回复负载一起出现。在这种情况下,您可以再次使用
EmbeddedJsonHeadersMessageMapper.toMessage()
将嵌入的头重新映射回
MessageHeaders
,或者您需要自己确保重新映射。在这种情况下,必须填充
replyChannel
标题,这一点很重要。最后,您只需在标准机制上进行回复,即可从标头向
replyChannel
发送输出。上面提到的
HeaderChannelRegistry
将确保将字符串id解析为实际的
TemporaryReplyChannel
实例,同时一开始网关仍将等待来自该
TemporaryReplyChannel
的值,很难说从这里发生了什么,但感觉像是一种竞争条件:您尝试发送到尚未注册或已删除的频道。如果你能在GitHub上分享一些简单的项目,让我们一起玩,那就太好了。@ArtemBilan我正试图在一个小的演示项目中重现这个错误。但现在我无法复制它。我会投入更多的时间,看看是否可能。还有其他的想法吗?我首先关心的是为什么不使用内置的
replyChannel
基于报头的请求-应答实现。另一个问题是,在使用这些动态注册的bean之后,您需要确保将它们从应用程序上下文中删除。@ArtemBilan我们使用这种方法,因为我们需要在系统后端中序列化为JSON的replyChannel的名称。现在,只有消息负载被序列化,而不是头字段。。。但这似乎值得再次思考。临时工。bean在finally块中被删除,请求处理结束。OK。我明白你的意思。让我想一想,我会回来给你一些解决方案,没有
会合频道
,甚至
路由器