Veröffentlichen von Publishern im Projektreaktor

1. Überblick

In diesem Artikel werden verschiedene Möglichkeiten zum Kombinieren von Publishers in Project Reactor beschrieben.

2. Abhängigkeiten von Maven

Lassen Sie uns unser Beispiel mit Project Reactor einrichten Abhängigkeiten:

<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-core</artifactId>
    <version>3.1.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-test</artifactId>
    <version>3.1.4.RELEASE</version>
    <scope>test</scope>
</dependency>

3. Verlage kombinieren

In einem Szenario, in dem mit Flux <T> oder Mono <T> gearbeitet werden muss, gibt es verschiedene Möglichkeiten, Streams zu kombinieren.

Lassen Sie uns einige Beispiele erstellen, um die Verwendung statischer Methoden in der Klasse Flux <T> wie concat, concatWith, merge, zip und __combineLatest.

In unseren Beispielen werden zwei Verleger des Typs Flux <Integer> verwendet, nämlich evenNumbers , die ein Flux von Integer ist und eine Folge gerader Zahlen enthält, die mit 1 (Variable min ) beginnen und auf 5 (Variable max ) begrenzt sind.

Wir erstellen oddNumbers , auch einen Flux vom Typ Integer mit ungeraden Zahlen:

Flux<Integer> evenNumbers = Flux
  .range(min, max)
  .filter(x -> x % 2 == 0);//i.e. 2, 4

Flux<Integer> oddNumbers = Flux
  .range(min, max)
  .filter(x -> x % 2 > 0); //ie. 1, 3, 5

3.1. c _oncat () _

Die Methode concat führt eine Verkettung der Eingaben aus, wobei Weiterleitungselemente von den nachgelagerten Quellen ausgegeben werden.

Die Verkettung wird erreicht, indem die erste Quelle sequentiell abonniert wird und dann darauf gewartet wird, dass sie abgeschlossen ist, bevor die nächste Quelle abonniert wird. Jeder Fehler unterbricht die Sequenz sofort und wird stromabwärts weitergeleitet.

Hier ist ein kurzes Beispiel:

@Test
public void givenFluxes__whenConcatIsInvoked__thenConcat() {
    Flux<Integer> fluxOfIntegers = Flux.concat(
      evenNumbers,
      oddNumbers);

    StepVerifier.create(fluxOfIntegers)
      .expectNext(2)
      .expectNext(4)
      .expectNext(1)
      .expectNext(3)
      .expectNext(5)
      .expectComplete()
      .verify();
}

3.2. ConcatWith ()

Mit der statischen Methode concatWith erzeugen wir als Ergebnis eine Verkettung von zwei Quellen vom Typ Flux <T> :

@Test
public void givenFluxes__whenConcatWithIsInvoked__thenConcatWith() {
    Flux<Integer> fluxOfIntegers = evenNumbers.concatWith(oddNumbers);

   //same stepVerifier as in the concat example above
}

3.3. c _ombineLatest () _

Die statische Flussmethode combineLatest generiert Daten, die durch die Kombination des zuletzt veröffentlichten Werts aus jeder der Publisher-Quellen bereitgestellt werden.

Hier ein Beispiel für die Verwendung dieser Methode mit zwei Publisher -Quellen und einer BiFunction als Parameter:

@Test
public void givenFluxes__whenCombineLatestIsInvoked__thenCombineLatest() {
    Flux<Integer> fluxOfIntegers = Flux.combineLatest(
      evenNumbers,
      oddNumbers,
      (a, b) -> a + b);

    StepVerifier.create(fluxOfIntegers)
      .expectNext(5)//4 + 1
      .expectNext(7)//4 + 3
      .expectNext(9)//4 + 5
      .expectComplete()
      .verify();
}

Wir können hier sehen, dass die Funktion combineLatest die Funktion "a b" mit dem neuesten Element von evenNumbers ( 4 ) und den Elementen von oddNumbers (1,3,5) angewendet hat, wodurch die Sequenz 5,7,9 generiert wird.

3.4. verschmelzen()

Die merge -Funktion führt ein Zusammenführen der Daten aus Publisher -Sequenzen, die in einem Array enthalten sind, zu einer verschachtelten zusammengeführten Sequenz aus:

@Test
public void givenFluxes__whenMergeIsInvoked__thenMerge() {
    Flux<Integer> fluxOfIntegers = Flux.merge(
      evenNumbers,
      oddNumbers);

    StepVerifier.create(fluxOfIntegers)
      .expectNext(2)
      .expectNext(4)
      .expectNext(1)
      .expectNext(3)
      .expectNext(5)
      .expectComplete()
      .verify();
}

Interessant ist, dass im Gegensatz zu _concat ( lazy-Abonnement ) _ die Quellen eifrig abonniert werden.

Hier sehen wir ein anderes Ergebnis der merge -Funktion, wenn wir eine Verzögerung zwischen den Elementen des Publishers einfügen:

@Test
public void givenFluxes__whenMergeWithDelayedElementsIsInvoked__thenMergeWithDelayedElements() {
    Flux<Integer> fluxOfIntegers = Flux.merge(
      evenNumbers.delayElements(Duration.ofMillis(500L)),
      oddNumbers.delayElements(Duration.ofMillis(300L)));

    StepVerifier.create(fluxOfIntegers)
      .expectNext(1)
      .expectNext(2)
      .expectNext(3)
      .expectNext(5)
      .expectNext(4)
      .expectComplete()
      .verify();
}

3.5. mergeSequential ()

Die mergeSequential -Methode führt Daten aus in einem Array bereitgestellten Publisher -Sequenzen zu einer geordneten zusammengeführten Sequenz zusammen.

Im Gegensatz zu concat werden Quellen eifrig abonniert.

Im Gegensatz zu merge werden ihre emittierten Werte in der abschließenden Reihenfolge in der Abonnementreihenfolge zusammengeführt:

@Test
public void testMergeSequential() {
    Flux<Integer> fluxOfIntegers = Flux.mergeSequential(
      evenNumbers,
      oddNumbers);

    StepVerifier.create(fluxOfIntegers)
      .expectNext(2)
      .expectNext(4)
      .expectNext(1)
      .expectNext(3)
      .expectNext(5)
      .expectComplete()
      .verify();
}

3.6. mergeDelayError ()

Der mergeDelayError führt Daten aus in einem Array enthaltenen Publisher-Sequenzen zu einer verschachtelten zusammengeführten Sequenz zusammen.

Im Gegensatz zu concat werden Quellen eifrig abonniert.

Diese Variante der statischen merge -Methode verzögert jeden Fehler, bis der Rest des Merge-Backlogs verarbeitet wurde.

Hier ist ein Beispiel für mergeDelayError:

@Test
public void givenFluxes__whenMergeWithDelayedElementsIsInvoked__thenMergeWithDelayedElements() {
    Flux<Integer> fluxOfIntegers = Flux.mergeDelayError(1,
      evenNumbers.delayElements(Duration.ofMillis(500L)),
      oddNumbers.delayElements(Duration.ofMillis(300L)));

    StepVerifier.create(fluxOfIntegers)
      .expectNext(1)
      .expectNext(2)
      .expectNext(3)
      .expectNext(5)
      .expectNext(4)
      .expectComplete()
      .verify();
}

3.7. verbinden mit()

Die statische Methode mergeWith führt Daten aus diesem Flux und einem Publisher zu einer verschachtelten zusammengeführten Sequenz zusammen.

Im Gegensatz zu concat werden innere Quellen gerne abonniert:

@Test
public void givenFluxes__whenMergeWithIsInvoked__thenMergeWith() {
    Flux<Integer> fluxOfIntegers = evenNumbers.mergeWith(oddNumbers);

   //same StepVerifier as in "3.4. Merge"
    StepVerifier.create(fluxOfIntegers)
      .expectNext(2)
      .expectNext(4)
      .expectNext(1)
      .expectNext(3)
      .expectNext(5)
      .expectComplete()
      .verify();
}

3.8. Postleitzahl() __

Die statische Methode zip agglutiniert mehrere Quellen zusammen, d. H. Wartet, bis alle Quellen ein Element ausgeben, und kombiniert diese Elemente zu einem Ausgabewert (aufgebaut aus der bereitgestellten Kombinatorfunktion).

Der Betreiber fährt damit fort, bis eine der Quellen vollständig ist:

@Test
public void givenFluxes__whenZipIsInvoked__thenZip() {
    Flux<Integer> fluxOfIntegers = Flux.zip(
      evenNumbers,
      oddNumbers,
      (a, b) -> a + b);

    StepVerifier.create(fluxOfIntegers)
      .expectNext(3)//2 + 1
      .expectNext(7)//4 + 3
      .expectComplete()
      .verify();
}

Da von evenNumbers kein Paar mehr zum Pairing vorhanden ist, wird das Element 5 von oddNumbers Publisher ignoriert.

3.9. z _ipWith () _

ZipWith führt dieselbe Methode aus wie zip , jedoch nur mit zwei Publishern:

@Test
public void givenFluxes__whenZipWithIsInvoked__thenZipWith() {
    Flux<Integer> fluxOfIntegers = evenNumbers
     .zipWith(oddNumbers, (a, b) -> a **  b);

    StepVerifier.create(fluxOfIntegers)
      .expectNext(2) //2 **  1
      .expectNext(12)//4 **  3
      .expectComplete()
      .verify();
}

4. Fazit

In diesem kurzen Tutorial haben wir mehrere Möglichkeiten zum Kombinieren von __Publishers entdeckt.

Die Beispiele sind wie immer unter https://github.com/eugenp/tutorials/tree/master/reactor-core [over auf GitHub verfügbar.