GH-3763: Add handleReactive() for Java DSL (#8605)

* GH-3763: Add `handleReactive()` for Java DSL

Fixes https://github.com/spring-projects/spring-integration/issues/3763

Add a convenient terminal operator to `BaseIntegrationFlowDefinition`
based on a `ReactiveMessageHandler`.
Also add an overload like `handleReactive(ReactiveMessageHandlerSpec)`
to let end-user to choose a protocol-specific channel adapter

* * Fix `Namespace Factory` wording in the `BaseIntegrationFlowDefinition` Javadocs

* Fix language in Docs

Co-authored-by: Gary Russell <grussell@vmware.com>

---------

Co-authored-by: Gary Russell <grussell@vmware.com>
This commit is contained in:
Artem Bilan
2023-05-01 15:24:00 -04:00
committed by GitHub
parent 8291fb952d
commit 212bd46d65
7 changed files with 109 additions and 17 deletions

View File

@@ -65,6 +65,7 @@ import org.springframework.integration.handler.LambdaMessageProcessor;
import org.springframework.integration.handler.LoggingHandler;
import org.springframework.integration.handler.MessageProcessor;
import org.springframework.integration.handler.MessageTriggerAction;
import org.springframework.integration.handler.ReactiveMessageHandlerAdapter;
import org.springframework.integration.handler.ServiceActivatingHandler;
import org.springframework.integration.router.AbstractMessageRouter;
import org.springframework.integration.router.ErrorMessageExceptionTypeRouter;
@@ -91,6 +92,7 @@ import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.ReactiveMessageHandler;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.InterceptableChannel;
import org.springframework.util.Assert;
@@ -891,7 +893,8 @@ public abstract class BaseIntegrationFlowDefinition<B extends BaseIntegrationFlo
/**
* Populate a {@link ServiceActivatingHandler} for the selected protocol specific
* {@link MessageHandler} implementation from {@code Namespace Factory}:
* {@link MessageHandler} implementation
* from the respective namespace factory (e.g. {@code Http, Kafka, Files}):
* <pre class="code">
* {@code
* .handle(Amqp.outboundAdapter(this.amqpTemplate).routingKeyExpression("headers.routingKey"))
@@ -1097,7 +1100,8 @@ public abstract class BaseIntegrationFlowDefinition<B extends BaseIntegrationFlo
/**
* Populate a {@link ServiceActivatingHandler} for the selected protocol specific
* {@link MessageHandler} implementation from {@code Namespace Factory}:
* {@link MessageHandler} implementation
* from the respective namespace factory (e.g. {@code Http, Kafka, Files}).
* In addition, accept options for the integration endpoint using {@link GenericEndpointSpec}.
* Typically, used with a Lambda expression:
* <pre class="code">
@@ -1221,7 +1225,7 @@ public abstract class BaseIntegrationFlowDefinition<B extends BaseIntegrationFlo
* Populate a {@link MessageTransformingHandler} for
* a {@link org.springframework.integration.transformer.HeaderEnricher}
* using header values from provided {@link MapBuilder}.
* Can be used together with {@code Namespace Factory}:
* Can be used together with a namespace factory:
* <pre class="code">
* {@code
* .enrichHeaders(Mail.headers()
@@ -1242,7 +1246,7 @@ public abstract class BaseIntegrationFlowDefinition<B extends BaseIntegrationFlo
* a {@link org.springframework.integration.transformer.HeaderEnricher}
* using header values from provided {@link MapBuilder}.
* In addition, accept options for the integration endpoint using {@link GenericEndpointSpec}.
* Can be used together with {@code Namespace Factory}:
* Can be used together with a namespace factory:
* <pre class="code">
* {@code
* .enrichHeaders(Mail.headers()
@@ -2916,6 +2920,68 @@ public abstract class BaseIntegrationFlowDefinition<B extends BaseIntegrationFlo
.get();
}
/**
* Populate a terminal consumer endpoint for the selected protocol specific
* {@link MessageHandler} implementation
* from the respective namespace factory (e.g. {@code Http, Kafka, Files}).
* In addition, accept options for the integration endpoint using {@link GenericEndpointSpec}.
* @param messageHandlerSpec the {@link MessageHandlerSpec} to configure the protocol specific
* {@link MessageHandler}.
* @param <H> the {@link MessageHandler} type.
* @return the current {@link BaseIntegrationFlowDefinition}.
* @since 6.1
*/
public <H extends ReactiveMessageHandler> IntegrationFlow handleReactive(
ReactiveMessageHandlerSpec<?, H> messageHandlerSpec) {
return handleReactive(messageHandlerSpec, null);
}
/**
* Populate a terminal consumer endpoint for the selected protocol specific
* {@link MessageHandler} implementation
* from the respective namespace factory (e.g. {@code Http, Kafka, Files}).
* In addition, accept options for the integration endpoint using {@link GenericEndpointSpec}.
* @param messageHandlerSpec the {@link MessageHandlerSpec} to configure the protocol specific
* {@link MessageHandler}.
* @param endpointConfigurer the {@link Consumer} to provide integration endpoint options.
* @param <H> the {@link MessageHandler} type.
* @return the current {@link BaseIntegrationFlowDefinition}.
* @since 6.1
*/
public <H extends ReactiveMessageHandler> IntegrationFlow handleReactive(
ReactiveMessageHandlerSpec<?, H> messageHandlerSpec,
@Nullable Consumer<GenericEndpointSpec<ReactiveMessageHandlerAdapter>> endpointConfigurer) {
return
addComponents(messageHandlerSpec.getComponentsToRegister()).
handleReactive(messageHandlerSpec.getObject().getDelegate(), endpointConfigurer);
}
/**
* Add a {@link ReactiveMessageHandler} as a terminal {@link IntegrationFlow} operator.
* @param reactiveMessageHandler the {@link ReactiveMessageHandler} to finish the flow.
* @return The {@link IntegrationFlow} instance based on this definition.
* @since 6.1
*/
public IntegrationFlow handleReactive(ReactiveMessageHandler reactiveMessageHandler) {
return handleReactive(reactiveMessageHandler, null);
}
/**
* Add a {@link ReactiveMessageHandler} as a terminal {@link IntegrationFlow} operator.
* @param reactiveMessageHandler the {@link ReactiveMessageHandler} to finish the flow.
* @param endpointConfigurer the {@link Consumer} to configure a target endpoint for the handler.
* @return The {@link IntegrationFlow} instance based on this definition.
* @since 6.1
*/
public IntegrationFlow handleReactive(ReactiveMessageHandler reactiveMessageHandler,
@Nullable Consumer<GenericEndpointSpec<ReactiveMessageHandlerAdapter>> endpointConfigurer) {
return handle(new ReactiveMessageHandlerAdapter(reactiveMessageHandler), endpointConfigurer)
.get();
}
/**
* Finish this flow with delegation to other {@link IntegrationFlow} instance.
* @param other the {@link IntegrationFlow} to compose with.

View File

@@ -70,7 +70,6 @@ import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.handler.LoggingHandler;
import org.springframework.integration.handler.ReactiveMessageHandlerAdapter;
import org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer;
import org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice;
import org.springframework.integration.handler.advice.RequestHandlerRetryAdvice;
@@ -718,8 +717,7 @@ public class IntegrationFlowTests {
public IntegrationFlow wireTapFlow1() {
return IntegrationFlow.from("tappedChannel1")
.wireTap("tapChannel", wt -> wt.selector(m -> m.getPayload().equals("foo")))
.handle(new ReactiveMessageHandlerAdapter((message) -> Mono.just(message).log().then()))
.get();
.handleReactive((message) -> Mono.just(message).log().then());
}
@Bean