Add toReactivePublisher(autoStartOnSubscribe) (#3657)

* Add `toReactivePublisher(autoStartOnSubscribe)`

The `IntegrationFlowBuilder.toReactivePublisher()` returns a `Publisher<Message<?>>`
which may be subscribed somewhere late in the application logic, e.g.
when WebSocket (or RSocket) subscription is initiated by the external client.
In between application context startup and that subscription moment, the `IntegrationFlow`
must not try to produce messages since there is nothing to consumer them from the
`Publisher<Message<?>>` side.
One of the way is to have a source endpoint not started automatically and control its
lifecycle from the point fo reactive subscription

* Introduce an `IntegrationFlowBuilder.toReactivePublisher(boolean autoStartOnSubscribe)`
to let the framework do a job for an `IntegrationFlow` lifecycle control.
This way end-user doesn't need to know autowire a starting endpoint and use `doOnSubscribe()`
and similar callbacks
* Change `ConsumerEndpointFactoryBean` log message about a `FixedSubscriberChannel`
to `INFO` since an `autoStartup = false` really does not have any effect and there is nothing
for end-user to worry about.
The `IntegrationFlow` knows nothing about each endpoint internals and cannot control which
mark as `autoStartup = false` and which not

* Fix languge in JavaDocs

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

Co-authored-by: Gary Russell <grussell@vmware.com>
This commit is contained in:
Artem Bilan
2021-11-01 16:49:59 -04:00
committed by GitHub
parent fc7d338302
commit eb4d583a17
6 changed files with 60 additions and 13 deletions

View File

@@ -54,6 +54,7 @@ import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import reactor.core.Disposable;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
@@ -104,19 +105,22 @@ public class ReactiveStreamsTests {
@Test
void testReactiveFlow() throws Exception {
assertThat(this.messageSource.isRunning()).isFalse();
List<String> results = new ArrayList<>();
CountDownLatch latch = new CountDownLatch(6);
Flux.from(this.publisher)
Disposable disposable =
Flux.from(this.publisher)
.map(m -> m.getPayload().toUpperCase())
.subscribe(p -> {
results.add(p);
latch.countDown();
});
this.messageSource.start();
assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
String[] strings = results.toArray(new String[0]);
assertThat(strings).isEqualTo(new String[]{ "A", "B", "C", "D", "E", "F" });
this.messageSource.stop();
disposable.dispose();
assertThat(this.messageSource.isRunning()).isFalse();
}
@Test
@@ -249,11 +253,10 @@ public class ReactiveStreamsTests {
return IntegrationFlows
.from(() -> new GenericMessage<>("a,b,c,d,e,f"),
e -> e.poller(p -> p.trigger(ctx -> this.invoked.getAndSet(true) ? null : new Date()))
.autoStartup(false)
.id("reactiveStreamsMessageSource"))
.split(String.class, p -> p.split(","))
.log()
.toReactivePublisher();
.toReactivePublisher(true);
}
@Bean