From 4736e2321544c110d5f7cd9239b91c482a972f4f Mon Sep 17 00:00:00 2001 From: abilan Date: Mon, 28 Nov 2022 14:12:12 -0500 Subject: [PATCH] GH-3953: Use lazy-load for output channels Fixes https://github.com/spring-projects/spring-integration/issues/3953 The replying `MessageHandler` can resolve the target output channel in on-demand manner. A new messaging annotations on `@Bean` parsing algorithm is missing the lazy-load opportunity and uses a `RuntimeBeanReference` for output channel options loading its bean eagerly. * Fix `AbstractMethodAnnotationPostProcessor` to use a `outputChannelName` and `defaultOutputChannelName` target properties for channel names to set. --- ...AbstractMethodAnnotationPostProcessor.java | 4 +-- ...ingAnnotationsWithBeanAnnotationTests.java | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java index 4645a584315..abd651d10c0 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java @@ -211,8 +211,8 @@ public void processBeanDefinition(String beanName, AnnotatedBeanDefinition beanD new BeanDefinitionPropertiesMapper(handlerBeanDefinition, annotations) .setPropertyValue(SEND_TIMEOUT_ATTRIBUTE) - .setPropertyReference("outputChannel") - .setPropertyReference("defaultOutputChannel"); + .setPropertyValue("outputChannel", "outputChannelName") + .setPropertyValue("defaultOutputChannel", "defaultOutputChannelName"); } if (isClassIn(handlerBeanClass, AbstractMessageProducingHandler.class, diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationsWithBeanAnnotationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationsWithBeanAnnotationTests.java index 599dff2b960..290d1f96bbc 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationsWithBeanAnnotationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationsWithBeanAnnotationTests.java @@ -47,6 +47,7 @@ import org.springframework.integration.aggregator.ExpressionEvaluatingReleaseStrategy; import org.springframework.integration.annotation.BridgeFrom; import org.springframework.integration.annotation.BridgeTo; +import org.springframework.integration.annotation.EndpointId; import org.springframework.integration.annotation.Filter; import org.springframework.integration.annotation.InboundChannelAdapter; import org.springframework.integration.annotation.Poller; @@ -63,6 +64,7 @@ import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.core.MessageSelector; import org.springframework.integration.core.MessageSource; +import org.springframework.integration.dsl.IntegrationFlow; import org.springframework.integration.endpoint.AbstractEndpoint; import org.springframework.integration.endpoint.EventDrivenConsumer; import org.springframework.integration.endpoint.SourcePollingChannelAdapter; @@ -70,7 +72,10 @@ import org.springframework.integration.history.MessageHistory; import org.springframework.integration.splitter.DefaultMessageSplitter; import org.springframework.integration.store.MessageGroup; +import org.springframework.integration.test.util.TestUtils; import org.springframework.integration.transformer.ExpressionEvaluatingTransformer; +import org.springframework.integration.transformer.MessageTransformingHandler; +import org.springframework.integration.transformer.ObjectToMapTransformer; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHandler; @@ -151,6 +156,10 @@ public class MessagingAnnotationsWithBeanAnnotationTests { @Autowired private CountDownLatch reactiveCustomizerLatch; + @Autowired + @Qualifier("objectToMapEndpoint.handler") + private MessageTransformingHandler objectToMapTransformerHandler; + @Test public void testMessagingAnnotationsFlow() throws InterruptedException { Stream.of(this.sourcePollingChannelAdapters).forEach(AbstractEndpoint::start); @@ -253,6 +262,18 @@ public void testReactiveMessageHandler() { .verifyComplete(); } + @Test + public void outputChannelIsLazyLoaded() { + assertThat(TestUtils.getPropertyValue(this.objectToMapTransformerHandler, "outputChannelName")) + .isEqualTo("lazilyCreatedChannel"); + + assertThat(TestUtils.getPropertyValue(this.objectToMapTransformerHandler, "outputChannel")).isNull(); + + assertThat(this.objectToMapTransformerHandler.getOutputChannel()) + .isInstanceOf(DirectChannel.class) + .extracting("beanName") + .isEqualTo("lazilyCreatedChannel"); + } @Configuration @EnableIntegration @@ -460,6 +481,20 @@ public ReactiveMessageHandler reactiveMessageHandlerService() { }; } + @Bean + @Transformer(inputChannel = "toMapChannel", outputChannel = "lazilyCreatedChannel") + @EndpointId("objectToMapEndpoint") + public ObjectToMapTransformer objectToMapTransformer() { + return new ObjectToMapTransformer(); + } + + @Bean + public IntegrationFlow lazyChannelFlow() { + return IntegrationFlow.from("lazilyCreatedChannel") + .log() + .nullChannel(); + } + } @Configuration