INT-4444: Introduce @Reactive & reactive() (#3503)
* INT-4444: Introduce `@Reactive` & `reactive()` JIRA: https://jira.spring.io/browse/INT-4444 Right now the high-level API creates a `ReactiveStreamsConsumer` only when the input channel is a `Publisher<?>` impl or target handler is a `ReactiveMessageHandler` * Add `@Reactive[] reactive()` attribute to messaging annotations * Add `ConsumerEndpointSpec.reactive()` Both options point to the same `ConsumerEndpointFactoryBean.setReactiveCustomizer()` making the target endpoint always as a `ReactiveStreamsConsumer` independently of the input channel and target handler * Use the `Function` to customize a source `Flux` from the channel * Test and document a new feature * * Fix links in docs * * Fix `ReactiveStreamsTests` * * Rework `reactive()` attribute of messaging annotations ot a single `@Reactive` value with default as `@Reactive(ValueConstants.DEFAULT_NONE)` * Fix language in docs * Fix `MessagingAnnotationUtils.resolveAttribute()` to use `requiredType.isInstance()` instead of comparing classes since annotation instances are `Proxy` at runtime
This commit is contained in:
@@ -471,6 +471,38 @@ Starting with version 4.3.3, the `@Poller` annotation has the `errorChannel` att
|
||||
This attribute plays the same role as `error-channel` in the `<poller>` XML component.
|
||||
See <<./endpoint.adoc#endpoint-namespace,Endpoint Namespace Support>> for more information.
|
||||
|
||||
The `poller()` attribute on the messaging annotations is mutually exclusive with the `reactive()` attribute.
|
||||
See next section for more information.
|
||||
|
||||
[[configuration-using-reactive-annotation]]
|
||||
==== Using `@Reactive` Annotation
|
||||
|
||||
The `ReactiveStreamsConsumer` has been around since version 5.0, but it was applied only when an input channel for the endpoint is a `FluxMessageChannel` (or any `org.reactivestreams.Publisher` implementation).
|
||||
Starting with version 5.3, its instance is also created by the framework when the target message handler is a `ReactiveMessageHandler` independently of the input channel type.
|
||||
The `@Reactive` sub-annotation (similar to mentioned above `@Poller`) has been introduced for all the messaging annotations starting with version 5.5.
|
||||
It accepts an optional `Function<? super Flux<Message<?>>, ? extends Publisher<Message<?>>>` bean reference and, independently of the input channel type and message handler, turns the target endpoint into the `ReactiveStreamsConsumer` instance.
|
||||
The function is used from the `Flux.transform()` operator to apply some customization (`publishOn()`, `doOnNext()`, `log()`, `retry()` etc.) on a reactive stream source from the input channel.
|
||||
|
||||
The following example demonstrates how to change the publishing thread from the input channel independently of the final subscriber and producer to that `DirectChannel`:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public Function<Flux<?>, Flux<?>> publishOnCustomizer() {
|
||||
return flux -> flux.publishOn(Schedulers.parallel());
|
||||
}
|
||||
|
||||
@ServiceActivator(inputChannel = "directChannel", reactive = @Reactive("publishOnCustomizer"))
|
||||
public void handleReactive(String payload) {
|
||||
...
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The `reactive()` attribute on the messaging annotations is mutually exclusive with the `poller()` attribute.
|
||||
See <<configuration-using-poller-annotation>> and <<./reactive-streams.adoc#reactive-streams, Reactive Streams Support>> for more information.
|
||||
|
||||
==== Using the `@InboundChannelAdapter` Annotation
|
||||
|
||||
Version 4.0 introduced the `@InboundChannelAdapter` method-level annotation.
|
||||
|
||||
@@ -262,6 +262,31 @@ See https://docs.spring.io/spring-integration/api/org/springframework/integratio
|
||||
IMPORTANT: If you use the DSL to construct a `PollerSpec` as a `@Bean`, do not call the `get()` method in the bean definition.
|
||||
The `PollerSpec` is a `FactoryBean` that generates the `PollerMetadata` object from the specification and initializes all of its properties.
|
||||
|
||||
[[java-dsl-reactive]]
|
||||
=== The `reactive()` Endpoint
|
||||
|
||||
Starting with version 5.5, the `ConsumerEndpointSpec` provides a `reactive()` configuration property with an optional customizer `Function<? super Flux<Message<?>>, ? extends Publisher<Message<?>>>`.
|
||||
This option configures the target endpoint as a `ReactiveStreamsConsumer` instance, independently of the input channel type, which is converted to a `Flux` via `IntegrationReactiveUtils.messageChannelToFlux()`.
|
||||
The provided function is used from the `Flux.transform()` operator to customize (`publishOn()`, `log()`, `doOnNext()` etc.) a reactive stream source from the input channel.
|
||||
|
||||
The following example demonstrates how to change the publishing thread from the input channel independently of the final subscriber and producer to that `DirectChannel`:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public IntegrationFlow reactiveEndpointFlow() {
|
||||
return IntegrationFlows
|
||||
.from("inputChannel")
|
||||
.<String, Integer>transform(Integer::parseInt,
|
||||
e -> e.reactive(flux -> flux.publishOn(Schedulers.parallel())))
|
||||
.get();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
See <<./reactive-streams.adoc#reactive-streams, Reactive Streams Support>> for more information.
|
||||
|
||||
[[java-dsl-endpoints]]
|
||||
=== DSL and Endpoint Configuration
|
||||
|
||||
|
||||
@@ -62,10 +62,14 @@ A consumer for the `FluxMessageChannel` must be a `org.reactivestreams.Subscribe
|
||||
Fortunately, all of the `MessageHandler` implementations in Spring Integration also implement a `CoreSubscriber` from project Reactor.
|
||||
And thanks to a `ReactiveStreamsConsumer` implementation in between, the whole integration flow configuration is left transparent for target developers.
|
||||
In this case, the flow behavior is changed from an imperative push model to a reactive pull model.
|
||||
A `ReactiveStreamsConsumer` can also be used to turn any `MessageChannel` into a reactive source using `MessageChannelReactiveUtils`, making an integration flow partially reactive.
|
||||
A `ReactiveStreamsConsumer` can also be used to turn any `MessageChannel` into a reactive source using `IntegrationReactiveUtils`, making an integration flow partially reactive.
|
||||
|
||||
See <<./channel.adoc#flux-message-channel,`FluxMessageChannel`>> for more information.
|
||||
|
||||
Starting with version 5.5, the `ConsumerEndpointSpec` introduces a `reactive()` option to make the endpoint in the flow as a `ReactiveStreamsConsumer` independently of the input channel.
|
||||
The optional `Function<? super Flux<Message<?>>, ? extends Publisher<Message<?>>>` can be provided to customise a source `Flux` from the input channel via `Flux.transform()` operation, e.g. with the `publishOn()`, `doOnNext()`, `retry()` etc.
|
||||
This functionality is represented as a `@Reactive` sub-annotation for all the messaging annotation (`@ServiceActivator`, `@Splitter` etc.) via their `reactive()` attribute.
|
||||
|
||||
=== Source Polling Channel Adapter
|
||||
|
||||
Usually, the `SourcePollingChannelAdapter` relies on the task which is initiated by the `TaskScheduler`.
|
||||
|
||||
@@ -30,6 +30,10 @@ An `AbstractPollingEndpoint` (source polling channel adapter and polling consume
|
||||
It can be changed to different value later on, e.g. via a Control Bus.
|
||||
See <<./endpoint.adoc#endpoint-pollingconsumer,Polling Consumer>> for more information.
|
||||
|
||||
The `ConsumerEndpointFactoryBean` now accept a `reactiveCustomizer` `Function` to any input channel as reactive stream source and use a `ReactiveStreamsConsumer` underneath.
|
||||
This is covered as a `ConsumerEndpointSpec.reactive()` option in Java DSL and as a `@Reactive` nested annotation for the messaging annotations.
|
||||
See <<./reactive-streams.adoc#reactive-streams,Reactive Streams Support>> for more information.
|
||||
|
||||
[[x5.5-amqp]]
|
||||
==== AMQP Changes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user