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:
Artem Bilan
2021-03-08 12:02:31 -05:00
committed by GitHub
parent f154088935
commit e9f234683e
23 changed files with 449 additions and 99 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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`.

View File

@@ -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