Зарегистрированный компонент RendezvousChannel не может быть найден в контексте приложения Spring - PullRequest
0 голосов
/ 04 сентября 2018

В приложении Spring Boot мы используем шаблон запрос-ответ, используя RendezvousChannel из Spring Integration. Когда мы получаем запрос, мы создаем канал с уникальным именем и регистрируем его в контексте приложения 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)

В настоящее время я не уверен, почему это происходит. Есть идеи по этому поводу?

1 Ответ

0 голосов
/ 05 сентября 2018

Для сценариев запрос-ответ мы рекомендуем использовать @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 обеспечит преобразование идентификатора строки в фактический экземпляр TemporaryReplyChannel, в то время как шлюз в начале все еще будет ожидать значения из этого TemporaryReplyChannel.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...