Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxJava, RxJava 2, Reactor : Etat de l’art des R...

David
April 06, 2017

RxJava, RxJava 2, Reactor : Etat de l’art des Reactive Streams en Java

2017 sera l’année des Reactive Streams en Java : RxJava est largement utilisé sur Android ou côté backend à travers Hystrix. RxJava 2 vient tout juste de sortir et va pouvoir profiter du chemin déjà tracé par sa précédente version. Pivotal pousse Reactor qui sera disponible dans le framework Spring version 5.

Qu’apportes ces différentes implémentations, en terme d’API ou de performances ? En quoi sont-elles différentes ? Faut-il migrer sur RxJava 2 tout de suite ? Reactor va-t’il remplacer RxJava et se limite t'il au framework Spring ?

Cette conférence fera un bref historique des ces bibliothèques avant de faire une comparaison des APIs, performances et cas d’utilisation de ces Reactive Streams.

Devoxx France ( Paris ) - 6 Avril 2017

David

April 06, 2017
Tweet

More Decks by David

Other Decks in Programming

Transcript

  1. Future ExecutorService ex = Executors.newCachedThreadPool();
 Future<String> future = ex.submit(() ->

    longProcessing());
 String result = future.get(); Appel bloquant
  2. Future Future<?> future1 = /* ... */
 Future<?> future2 =

    /* ... */
 Future<?> future3 = /* ... */
 Future<?> future4 = /* ... */
 Future<?> future5 = /* ... */ Orchestration optimale ?
  3. Callback RemoteService service = buildRemoteService();
 service.getUser(id -> {
 service.getData(id, data

    -> {
 service.getSomething(data, whut -> { service.neverEndingCallBack(whut, () -> { }); });
 });
 }); Callback Hell
  4. RxJava n’est pas compatible 
 avec Reactive Streams (il faut

    alors utiliser un adapteur : RxJavaReactiveStreams) https://github.com/ReactiveX/RxJavaReactiveStreams
  5. onNext * ( onError | onComplete ) 
 onNext *

    ( onError | onCompleted ) RxJava Reactive Streams
  6. onNext * ( onError | onComplete ) 
 onNext *

    ( onError | onCompleted ) RxJava Reactive Streams Nom différent
  7. API pour manipuler 
 des événements de manière synchrone ou

    asynchrone à travers un flux d’événements
  8. remoteApi.people(1).flatMap(luke -> { 
 Observable<String> vehicles = Observable.from(luke.getVehiclesIds())
 .flatMap(remoteApi::vehicle)
 .map(vehicle

    -> luke.getName() + " can drive " + vehicle.getName());
 
 Observable<String> starships = Observable.from(luke.getStarshipsIds())
 .flatMap(remoteApi::starship)
 .map(starship -> luke.getName() + " can fly with " + starship.getName());
 
 return Observable.merge(vehicles, starships); 
 }).subscribe(System.out::println);
  9. remoteApi.people(1).flatMap(luke -> { 
 Observable<String> vehicles = Observable.from(luke.getVehiclesIds())
 .flatMap(remoteApi::vehicle)
 .map(vehicle

    -> luke.getName() + " can drive " + vehicle.getName());
 
 Observable<String> starships = Observable.from(luke.getStarshipsIds())
 .flatMap(remoteApi::starship)
 .map(starship -> luke.getName() + " can fly with " + starship.getName());
 
 return Observable.merge(vehicles, starships); 
 }).subscribe(System.out::println);
  10. remoteApi.people(1).flatMap(luke -> { 
 Observable<String> vehicles = Observable.from(luke.getVehiclesIds())
 .flatMap(remoteApi::vehicle)
 .map(vehicle

    -> luke.getName() + " can drive " + vehicle.getName());
 
 Observable<String> starships = Observable.from(luke.getStarshipsIds())
 .flatMap(remoteApi::starship)
 .map(starship -> luke.getName() + " can fly with " + starship.getName());
 
 return Observable.merge(vehicles, starships); 
 }).subscribe(System.out::println); Push du résultat
  11. remoteApi.people(1).flatMap(luke -> { 
 Observable<String> vehicles = Observable.from(luke.getVehiclesIds())
 .flatMap(remoteApi::vehicle)
 .map(vehicle

    -> luke.getName() + " can drive " + vehicle.getName());
 
 Observable<String> starships = Observable.from(luke.getStarshipsIds())
 .flatMap(remoteApi::starship)
 .map(starship -> luke.getName() + " can fly with " + starship.getName());
 
 return Observable.merge(vehicles, starships); 
 }).subscribe(System.out::println); Récupération des véhicules de Luke Récupération des vaisseaux de Luke
  12. remoteApi.people(1).flatMap(luke -> { 
 Observable<String> vehicles = Observable.from(luke.getVehiclesIds())
 .flatMap(remoteApi::vehicle)
 .map(vehicle

    -> luke.getName() + " can drive " + vehicle.getName());
 
 Observable<String> starships = Observable.from(luke.getStarshipsIds())
 .flatMap(remoteApi::starship)
 .map(starship -> luke.getName() + " can fly with " + starship.getName());
 
 return Observable.merge(vehicles, starships); 
 }).subscribe(System.out::println); Flux 
 d’événements Flux 
 d’événements
  13. remoteApi.people(1).flatMap(luke -> { 
 Observable<String> vehicles = Observable.from(luke.getVehiclesIds())
 .flatMap(remoteApi::vehicle)
 .map(vehicle

    -> luke.getName() + " can drive " + vehicle.getName());
 
 Observable<String> starships = Observable.from(luke.getStarshipsIds())
 .flatMap(remoteApi::starship)
 .map(starship -> luke.getName() + " can fly with " + starship.getName());
 
 return Observable.merge(vehicles, starships); 
 }).subscribe(System.out::println); Fusion des 2 flux
  14. remoteApi.people(1).flatMap(luke -> { 
 Observable<String> vehicles = Observable.from(luke.getVehiclesIds())
 .flatMap(remoteApi::vehicle)
 .map(vehicle

    -> luke.getName() + " can drive " + vehicle.getName());
 
 Observable<String> starships = Observable.from(luke.getStarshipsIds())
 .flatMap(remoteApi::starship)
 .map(starship -> luke.getName() + " can fly with " + starship.getName());
 
 return Observable.merge(vehicles, starships); 
 }).subscribe(System.out::println); Déclenche l’exécution du code
  15. remoteApi.people(1).flatMap(luke -> { 
 Observable<String> vehicles = Observable.from(luke.getVehiclesIds())
 .flatMap(remoteApi::vehicle)
 .map(vehicle

    -> luke.getName() + " can drive " + vehicle.getName());
 
 Observable<String> starships = Observable.from(luke.getStarshipsIds())
 .flatMap(remoteApi::starship)
 .map(starship -> luke.getName() + " can fly with " + starship.getName());
 
 return Observable.merge(vehicles, starships); 
 }).subscribe(System.out::println); Flux 
 d’événements
  16. Button btn = new Button();
 btn.setText("Click Me");
 
 JavaFx.fromClick(btn) 


    .observeOn(Schedulers.io()) 
 .switchMap(evt -> remoteApi.getData())
 .observeOn(javaFx()) 
 .doOnNext(value -> btn.setText("Data: " + value))
 .subscribe();
  17. Button btn = new Button();
 btn.setText("Click Me");
 
 JavaFx.fromClick(btn) //

    Observable<Event>
 .observeOn(Schedulers.io())
 .switchMap(evt -> remoteApi.getData())
 .observeOn(javaFx()) 
 .doOnNext(value -> btn.setText("Data: " + value))
 .subscribe(); Écoute des clicks
  18. Button btn = new Button();
 btn.setText("Click Me");
 
 JavaFx.fromClick(btn) //

    Observable<Event>
 .observeOn(Schedulers.io())
 .switchMap(evt -> remoteApi.getData())
 .observeOn(javaFx()) 
 .doOnNext(value -> btn.setText("Data: " + value))
 .subscribe(); Changement du contexte d’exécution
  19. Button btn = new Button();
 btn.setText("Click Me");
 
 JavaFx.fromClick(btn) //

    Observable<Event>
 .observeOn(Schedulers.io())
 .switchMap(evt -> remoteApi.getData()) // Observable<Data>
 .observeOn(javaFx()) 
 .doOnNext(value -> btn.setText("Data: " + value))
 .subscribe(); Appel asynchrone d’un web service
  20. Button btn = new Button();
 btn.setText("Click Me");
 
 JavaFx.fromClick(btn) //

    Observable<Event>
 .observeOn(Schedulers.io())
 .switchMap(evt -> remoteApi.getData()) // Observable<Data>
 .observeOn(javaFx()) 
 .doOnNext(value -> btn.setText("Data: " + value))
 .subscribe(); Changement du contexte d’exécution
  21. Button btn = new Button();
 btn.setText("Click Me");
 
 JavaFx.fromClick(btn) //

    Observable<Event>
 .observeOn(Schedulers.io())
 .switchMap(evt -> remoteApi.getData()) // Observable<Data>
 .observeOn(javaFx()) 
 .doOnNext(value -> btn.setText("Data: " + value))
 .subscribe(); Changement au niveau de l’UI
  22. Button btn = new Button();
 btn.setText("Click Me");
 
 JavaFx.fromClick(btn) //

    Observable<Event>
 .observeOn(Schedulers.io())
 .switchMap(evt -> remoteApi.getData()) // Observable<Data>
 .observeOn(javaFx()) 
 .doOnNext(value -> btn.setText("Data: " + value))
 .subscribe(); Flux 
 d’événements
  23. Button btn = new Button();
 btn.setText("Click Me");
 
 ExecutorService io

    = Executors.newSingleThreadExecutor();
 btn.setOnAction(evt -> {
 io.submit(() -> {
 remoteApi.getData(data -> {
 Platform.runLater(() -> {
 btn.setText(data);
 });
 });
 });
 }); Sac de noeud Structure pyramidale
  24. Création des 
 Reactive Extensions Création de RxJava Participation active

    Reprise de 
 RxJava & RxJava 2 Création de Reactor Participation à Reactor
  25. RxJava Contrat Backpressure Observable [N] Oui Single [1] Non Completable

    [0] Non Ajouté après coup Appel Web service Processus d’arrière plan
  26. Écouter une websocket, pour c h a q u e

    c o m m a n d e r e ç u e , composer une réponse à partir de 3 webservices différents, puis exécuter 2 jobs séquentiellement ?
  27. Écouter une websocket, pour c h a q u e

    c o m m a n d e r e ç u e , composer une réponse à partir de 3 webservices différents, puis exécuter 2 jobs séquentiellement ?
  28. Écouter une websocket, pour c h a q u e

    c o m m a n d e r e ç u e , composer une réponse à partir de 3 webservices différents, puis exécuter 2 jobs séquentiellement ?
  29. Écouter une websocket, pour c h a q u e

    c o m m a n d e r e ç u e , composer une réponse à partir de 3 webservices différents, puis exécuter 2 jobs séquentiellement ?
  30. websocket("/topics/cmd")
 .observeOn(Schedulers.io())
 .switchMap(cmd ->
 Single.zip(
 api.getActions(),
 api.getScore(),
 api.getUserData(),
 this::composeResult).toObservable())
 .observeOn(Schedulers.computation())


    .concatMap(result -> updateDb(result).andThen(getLastResults()))
 .subscribe(last -> System.out.println("last results -> " + last)); Écoute de la websocket Observable
  31. websocket("/topics/cmd")
 .observeOn(Schedulers.io())
 .switchMap(cmd ->
 Single.zip(
 api.getActions(),
 api.getScore(),
 api.getUserData(),
 this::composeResult).toObservable())
 .observeOn(Schedulers.computation())


    .concatMap(result -> updateDb(result).andThen(getLastResults()))
 .subscribe(last -> System.out.println("last results -> " + last)); Composition d’une réponse à partir de 3 webservices Single
  32. websocket("/topics/cmd")
 .observeOn(Schedulers.io())
 .switchMap(cmd ->
 Single.zip(
 api.getActions(),
 api.getScore(),
 api.getUserData(),
 this::composeResult).toObservable())
 .observeOn(Schedulers.computation())


    .concatMap(result -> updateDb(result).andThen(getLastResults()))
 .subscribe(last -> System.out.println("last results -> " + last)); Completable Exécuter 2 jobs
  33. websocket("/topics/cmd")
 .observeOn(Schedulers.io())
 .switchMap(cmd ->
 Single.zip(
 api.getActions(),
 api.getScore(),
 api.getUserData(),
 this::composeResult).toObservable())
 .observeOn(Schedulers.computation())


    .concatMap(result -> updateDb(result).andThen(getLastResults()))
 .subscribe(last -> System.out.println("last results -> " + last)); Écoute de la websocket Observable Composition d’une réponse à partir de 3 webservices Single Completable Exécuter 2 jobs
  34. RxJava 2 Contrat Backpressure Observable [N] Non Single [1] Non

    Completable [0] Non Maybe [0|1] Non Nouveau ! Concept « similaire » à Optional
  35. acceptedIntent
 .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false))
 .concatMap(intent -> approximatedEngine.detectCurrentPlace())
 .doOnNext(score ->

    Log.info(TAG, "Scan completed with result " + score))
 .concatMap(this::detectSleepMode)
 .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score))
 .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p))
 .subscribe()
  36. acceptedIntent
 .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false)) .onBackpressureDrop()
 .concatMap(intent -> approximatedEngine.detectCurrentPlace())
 .doOnNext(score

    -> Log.info(TAG, "Scan completed with result " + score))
 .onBackpressureDrop() .concatMap(this::detectSleepMode)
 .onBackpressureDrop()
 .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score))
 .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p))
 .subscribe() Ajouté dans un moment de panique
  37. RxJava 2 Contrat Backpressure Observable [N] Non Single [1] Non

    Completable [0] Non Maybe [0|1] Non Nouveau ! Concept « similaire » à Optional
  38. RxJava 2 Contrat Backpressure Observable [N] Non Single [1] Non

    Completable [0] Non Maybe [0|1] Non Flowable [N] Oui Nouveau ! Observable avec 
 back pressure Concept « similaire » à Optional
  39. Observable → moins de 1000 éléments → Gestion d’élément d’interface

    graphique → Remplacement de Stream Java Flowable → plus de 10 000 éléments → contrôle de l’émission de données → Flux réseau avec contrôle de débit
  40. Reactor Contrat Backpressure Flux [N] Oui Mono [0|1] Oui Identique

    à Flowable Flux avec 
 au maximum 
 1 élément
  41. Observable.range(1, 10)
 .to(obs -> RxJava2Adapter.observableToFlux(obs, BackpressureStrategy.BUFFER))
 .checkpoint()
 .subscribe(); Maybe.empty()
 .to(maybe

    -> RxJava2Adapter.maybeToMono(maybe))
 .checkpoint()
 .subscribe(); Single.just(1)
 .to(single -> RxJava2Adapter.singleToMono(single))
 .checkpoint()
 .subscribe(); Observable → Flux Single → Mono Maybe → Mono
  42. P o u v o i r u t i

    l i s e r u n e biblio t hèq ue utilisant RxJava 2 dans son projet Reactor (et vice versa)
  43. all amb ambArray ambWith any as awaitOnSubscribe blockFirst blockFirstMillis blockLast

    blockLastMillis blockingFirst blockingForEach blockingIterable blockingLast blockingLatest blockingMostRecent blockingNext blockingSingle blockingSubscribe buffer bufferMillis bufferSize bufferTimeout bufferTimeoutMillis bufferUntil bufferWhile cache cacheWithInitialCapacity cancelOn cast checkpoint collect collectInto collectList collectMap collectMultimap collectSortedList combineLatest combineLatestDelayError compose concat concatArray concatArrayDelayError concatArrayEager concatDelayError concatEager concatMap concatMapDelayError concatMapEager concatMapEagerDelayError concatMapIterable concatWith contains count create debounce defaultIfEmpty defer delay delayElements delayElementsMillis delayMillis delaySubscription delaySubscriptionMillis dematerialize distinct distinctUntilChanged doAfterNext doAfterTerminate doFinally doOnCancel doOnComplete doOnEach doOnError doOnLifecycle doOnNext doOnRequest doOnSubscribe doOnTerminate elapsed elementAt elementAtOrError empty equals error filter first firstElement firstEmitting firstEmittingWith firstOrError flatMap flatMapCompletable flatMapIterable flatMapMaybe flatMapSequential flatMapSingle forEach forEachWhile from fromArray fromCallable fromFuture fromIterable fromPublisher fromStream generate getClass getPrefetch groupBy groupJoin handle hasElement hasElements hashCode hide ignoreElements interval intervalMillis intervalRange isEmpty join just last lastElement lastOrError lift limitRate log map mapError materialize merge mergeArray mergeArrayDelayError mergeDelayError mergeSequential mergeWith never next notify notifyAll observeOn ofType onBackpressureBuffer onBackpressureDrop onBackpressureError onBackpressureLatest onErrorResumeNext onErrorResumeWith onErrorReturn onErrorReturnItem onExceptionResumeNext onTerminateDetach parallel publish publishNext publishOn range rangeLong rebatchRequests reduce reduceWith repeat repeatUntil repeatWhen replay replayMillis retry retryUntil retryWhen safeSubscribe sample sampleFirst sampleFirstMillis sampleMillis sampleTimeout scan scanWith sequenceEqual serialize share single singleElement singleOrEmpty singleOrError skip skipLast skipMillis skipUntil skipUntilOther skipWhile sort sorted startWith startWithArray strict subscribe subscribeOn subscribeWith switchIfEmpty switchMap switchMapDelayError switchOnError switchOnNext switchOnNextDelayError take takeLast takeMillis takeUntil takeUntilOther takeWhile test then thenEmpty thenMany throttleFirst throttleLast throttleWithTimeout timeInterval timeout timeoutMillis timer timestamp to toFuture toIterable toList toMap toMultimap toObservable toSortedList toStream toString transform unsafeCreate unsubscribeOn using wait window windowMillis windowTimeout windowTimeoutMillis windowUntil windowWhile withLatestFrom zip zipArray zipIterable zipWith zipWithIterable
  44. RxJava RxJava 2 Reactor flatMap flatMap flatMap Émission d’aucune, une

    ou plusieurs valeurs amb amb firstEmitting Émission des valeurs du flux répondant en premier … … … … debounce debounce N/A Ignore les événements pendant un laps de temps
  45. RxJava RxJava 2 Reactor flatMap flatMap flatMap Émission d’aucune, une

    ou plusieurs valeurs amb amb firstEmitting Émission des valeurs du flux répondant en premier … … … … debounce debounce N/A Ignore les événements pendant un laps de temps Renommage
  46. https://github.com/ReactiveX/RxJava/wiki/Implementing-custom-operators-(draft) writing operators is hard when one writes an operator,

    the Observable protocol, unsubscription, backpressure and concurrency have to be taken into account and adhered to the letter
  47. -Jake Wharton « Unless you can model your entire system

    synchronously, a single asynchronous source breaks imperative programming »
  48. -Jake Wharton « Unless you can model your entire system

    synchronously, a single asynchronous source breaks imperative programming »
  49. RxJava
 RxJava 2 Reactor Flowable.just Flux.just Émission d’une valeur existante

    Flowable.defer Flux.defer Émission tardive d’un Observable Flowable.fromCallable Mono.fromCallable Émission à partir d’un appel de fonction Flowable.create Flux.create Contrôle manuel de l’émission des événements Flowable.using Flux.using Gestion d’une ressource Flowable.fromPublisher Flux.from Utilisation d’un Publisher (Reactive Streams) Flowable.generate Flux.generate Utilisation d’un générateur de valeurs
  50. RxJava
 RxJava 2 Reactor Flowable.just Flux.just Émission d’une valeur existante

    Flowable.defer Flux.defer Émission tardive d’un Observable Flowable.fromCallable Mono.fromCallable Émission à partir d’un appel de fonction Flowable.create Flux.create Contrôle manuel de l’émission des événements Flowable.using Flux.using Gestion d’une ressource Flowable.fromPublisher Flux.from Utilisation d’un Publisher (Reactive Streams) Flowable.generate Flux.generate Utilisation d’un générateur de valeurs
  51. RxJava
 RxJava 2 Reactor Flowable.just Flux.just Émission d’une valeur existante

    Flowable.defer Flux.defer Émission tardive d’un Observable Flowable.fromCallable Mono.fromCallable Émission à partir d’un appel de fonction Flowable.create Flux.create Contrôle manuel de l’émission des événements Flowable.using Flux.using Gestion d’une ressource Flowable.fromPublisher Flux.from Utilisation d’un Publisher (Reactive Streams) Flowable.generate Flux.generate Utilisation d’un générateur de valeurs
  52. RxJava
 RxJava 2 Reactor Flowable.just Flux.just Émission d’une valeur existante

    Flowable.defer Flux.defer Émission tardive d’un Observable Flowable.fromCallable Mono.fromCallable Émission à partir d’un appel de fonction Flowable.create Flux.create Contrôle manuel de l’émission des événements Flowable.using Flux.using Gestion d’une ressource Flowable.fromPublisher Flux.from Utilisation d’un Publisher (Reactive Streams) Flowable.generate Flux.generate Utilisation d’un générateur de valeurs
  53. RxJava
 RxJava 2 Reactor Flowable.just Flux.just Émission d’une valeur existante

    Flowable.defer Flux.defer Émission tardive d’un Observable Flowable.fromCallable Mono.fromCallable Émission à partir d’un appel de fonction Flowable.create Flux.create Contrôle manuel de l’émission des événements Flowable.using Flux.using Gestion d’une ressource Flowable.fromPublisher Flux.from Utilisation d’un Publisher (Reactive Streams) Flowable.generate Flux.generate Utilisation d’un générateur de valeurs
  54. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis")
 private String redis() throws InterruptedException {
 CountDownLatch latch = new CountDownLatch(1);
 AtomicReference<String> result = new AtomicReference<>();
 this.connection.subscribe((message, pattern) -> {
 result.set(message.toString());
 latch.countDown();
 }, TOPIC_NAME);
 latch.await();
 return result.get();
 } }
  55. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis")
 private String redis() throws InterruptedException {
 CountDownLatch latch = new CountDownLatch(1);
 AtomicReference<String> result = new AtomicReference<>();
 this.connection.subscribe((message, pattern) -> {
 result.set(message.toString());
 latch.countDown();
 }, TOPIC_NAME);
 latch.await();
 return result.get();
 } } Écoute de Redis
  56. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis")
 private String redis() throws InterruptedException {
 CountDownLatch latch = new CountDownLatch(1);
 AtomicReference<String> result = new AtomicReference<>();
 this.connection.subscribe((message, pattern) -> {
 result.set(message.toString());
 latch.countDown();
 }, TOPIC_NAME);
 latch.await();
 return result.get();
 } } Code de synchronisation Code de synchronisation
  57. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis")
 private String redis() throws InterruptedException {
 
 String result = Flowable.create(sub -> {
 this.connection.subscribe((message, pattern) -> {
 sub.onNext(message.toString());
 sub.onComplete();
 }, TOPIC_NAME);
 }, BackpressureStrategy.BUFFER)
 .blockingFirst();
 return result;
 } }
  58. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis")
 private String redis() throws InterruptedException {
 
 String result = Flowable.create(sub -> {
 this.connection.subscribe((message, pattern) -> {
 sub.onNext(message.toString());
 sub.onComplete();
 }, TOPIC_NAME);
 }, BackpressureStrategy.BUFFER)
 .blockingFirst();
 return result;
 } } Encapsulation Synchronisation Contract Reactive
  59. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis")
 private DeferredResult<String> redis() throws InterruptedException {
 
 DeferredResult<String> result = new DeferredResult<>(10_000l);
 
 Flowable.create(sub -> {
 this.connection.subscribe((message, pattern) -> {
 sub.onNext(message.toString());
 sub.onComplete();
 }, TOPIC_NAME);
 }, BackpressureStrategy.BUFFER)
 .subscribe(result::setResult);
 
 return result;
 }
  60. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis")
 private DeferredResult<String> redis() throws InterruptedException {
 
 DeferredResult<String> result = new DeferredResult<>(10_000l);
 
 Flowable.create(sub -> {
 this.connection.subscribe((message, pattern) -> {
 sub.onNext(message.toString());
 sub.onComplete();
 }, TOPIC_NAME);
 }, BackpressureStrategy.BUFFER)
 .subscribe(result::setResult);
 
 return result;
 } Résultat tardif Utilisation de DeferredResult
  61. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
 private Flux<String> redis() throws InterruptedException {
 
 Flowable<String> rxjava = Flowable.create(sub -> {
 this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()), TOPIC_NAME);
 }, BackpressureStrategy.BUFFER);
 
 return Flux.defer(() -> rxjava);
 } }
  62. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
 private Flux<String> redis() throws InterruptedException {
 
 Flowable<String> rxjava = Flowable.create(sub -> {
 this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()), TOPIC_NAME);
 }, BackpressureStrategy.BUFFER);
 
 return Flux.defer(() -> rxjava);
 } } RxJava 2 → Flux Flux → SSE
  63. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
 private Publisher<String> redis() throws InterruptedException {
 return Flowable.create(sub -> {
 this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()), TOPIC_NAME);
 }, BackpressureStrategy.BUFFER);
 
 }
  64. @RestController
 public class HelloController {
 
 private static final byte[]

    TOPIC_NAME = "topic".getBytes();
 
 @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
 private Publisher<String> redis() throws InterruptedException {
 return Flowable.create(sub -> {
 this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()), TOPIC_NAME);
 }, BackpressureStrategy.BUFFER);
 
 } Publisher
  65. RxJavaInterop.toV2Observable(rx.Observable.just(1, 2, 3))
 .firstElement()
 .subscribe();
 
 RxJavaInterop.toV1Observable(io.reactivex.Observable.just(1, 2, 3), 


    BackpressureStrategy.DROP)
 .first()
 .subscribe(); https://github.com/akarnokd/RxJava2Interop RxJava → RxJava 2 RxJava 2 → RxJava
  66. Observable.just(null);
 
 Single.just(null);
 
 Observable.fromCallable(() -> null)
 .subscribe(System.out::println, Throwable::printStackTrace);
 


    Observable.just(1).map(v -> null)
 .subscribe(System.out::println, Throwable::printStackTrace); NullPointerException NullPointerException NullPointerException N ullPointerException
  67. rx.Action1 rx.Func1 RxJava RxJava 2 rx.Func2 rx.Func3 rx.Action2 io.reactivex.functions.Consumer io.reactivex.functions.Function

    io.reactivex.functions.BiFunction io.reactivex.functions.Function3 io.reactivex.functions.BiConsumer Suivre les conventions Java 8
  68. JavaFx.fromClick(btn) 
 .observeOn(Schedulers.io())
 .switchMap(evt -> remoteApi.getData())
 .observeOn(Schedulers.computation())
 .flatMap(data -> intensiveComputation(data))


    .observeOn(javaFx())
 .doOnNext(value -> btn.setText("Data: " + value)) 
 .subscribe(); entrée/sortie calculs Thread graphique
  69. RxJava RxJava 2 Reactor Description io() io() elastic() Pool de

    Thread qui grossit au besoin computation() computation() parallel() Pool fini de Thread single() single() single() Pool de 1 Thread immediate() immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  70. RxJava RxJava 2 Reactor Description io() io() elastic() Pool de

    Thread qui grossit au besoin computation() computation() parallel() Pool fini de Thread single() single() single() Pool de 1 Thread immediate() immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  71. RxJava RxJava 2 Reactor Description io() io() elastic() Pool de

    Thread qui grossit au besoin computation() computation() parallel() Pool fini de Thread single() single() single() Pool de 1 Thread immediate() immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  72. RxJava RxJava 2 Reactor Description io() io() elastic() Pool de

    Thread qui grossit au besoin computation() computation() parallel() Pool fini de Thread single() single() single() Pool de 1 Thread immediate() immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  73. RxJava RxJava 2 Reactor Description io() io() elastic() Pool de

    Thread qui grossit au besoin computation() computation() parallel() Pool fini de Thread single() single() single() Pool de 1 Thread immediate() immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer Absent pour votre bien
  74. RxJava RxJava 2 Reactor Description io() io() elastic() Pool de

    Thread qui grossit au besoin computation() computation() parallel() Pool fini de Thread single() single() single() Pool de 1 Thread immediate() immediate() Execute la tâche immédiatement trampoline() trampoline() Ajoute la tâche dans une file d’attente avant de l’executer
  75. Flowable.range(1, 100000)
 .subscribe(new Subscriber<Integer>() {
 
 private Subscription source;
 


    @Override
 public void onSubscribe(Subscription s) {
 this.source = s;
 this.source.request(1);
 }
 
 @Override
 public void onNext(Integer o) {
 longComputation(o);
 this.source.request(1);
 }
 });
  76. Flowable.range(1, 100000)
 .subscribe(new Subscriber<Integer>() {
 
 private Subscription source;
 


    @Override
 public void onSubscribe(Subscription s) {
 this.source = s;
 this.source.request(1);
 }
 
 @Override
 public void onNext(Integer o) {
 longComputation(o);
 this.source.request(1);
 }
 }); Garder la référence de l’abonnement Demander l’émission des éléments suivants Demande l’émission des premiers éléments
  77. Flowable.range(1, 100000)
 .subscribe(new Subscriber<Integer>() {
 
 private Subscription source;
 


    @Override
 public void onSubscribe(Subscription s) {
 this.source = s;
 this.source.request(1);
 }
 
 @Override
 public void onNext(Integer o) {
 longComputation(o);
 this.source.request(1);
 }
 }); Contrôle de l’émission
  78. source()
 .subscribe(new Subscriber<Integer>() {
 
 private Subscription source;
 
 @Override


    public void onSubscribe(Subscription s) {
 this.source = s;
 this.source.request(1);
 }
 
 @Override
 public void onNext(Integer o) {
 longComputation(o);
 this.source.request(1);
 }
 }); Kafka JDBC Fichier
  79. rx.exceptions.OnErrorNotImplementedException: Sequence contains too many elements at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java: 386) at

    rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java: 383) at rx.internal.util.ActionSubscriber.onError(ActionSubscriber.java:44) at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:153) at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115) at rx.internal.operators.OperatorSingle$ParentSubscriber.onNext(OperatorSingle.java:97) at rx.internal.operators.OnSubscribeRange$RangeProducer.slowPath(OnSubscribeRange.java:90) at rx.internal.operators.OnSubscribeRange$RangeProducer.request(OnSubscribeRange.java:68) at rx.Subscriber.setProducer(Subscriber.java:211) at rx.internal.operators.OnSubscribeRange.call(OnSubscribeRange.java:38) Stacktrace inexploitable
  80. RxJavaHooks.enableAssemblyTracking(); […] Caused by: rx.exceptions.AssemblyStackTraceException: Assembly trace: at rx.Observable.create(Observable.java:100) at

    rx.Observable.lift(Observable.java:237) at rx.Observable.single(Observable.java:9330) at rxjava2.BasicExampleTest.stacktrace(BasicExampleTest.java:225) rx.Observable.range(1, 100)
 .single()
 .subscribe();
  81. enableTracing n’est pas encore supporté par RxJava 2 (pour cela,

    il faut utiliser RxJava2Extensions) https://github.com/akarnokd/RxJava2Extensions
  82. Flux.range(1, 100)
 .single()
 .checkpoint("label")
 .subscribe(…); Assembly trace from producer [reactor.core.publisher.MonoSingle],

    described as [label] : reactor.core.publisher.Mono.checkpoint(Mono.java:1304) rxjava2.BasicExampleTest.stacktraceReactor(BasicExampleTest.java:236) Error has been observed by the following operator(s): |_ Mono.checkpoint(BasicExampleTest.java:236)
  83. for (int x = 0; x < 10_000; x++) {


    
 Observable.interval(10, TimeUnit.MILLISECONDS)
 .takeWhile(i -> take.get())
 .flatMap(i -> Observable.range(1, 100))
 .subscribe();
 }
  84. RxJava RxJava 2 Reactor Retrofit Oui Oui Non RxAndroid Oui

    Oui Non Realm Oui Non Non Hystrix Oui Non Non Couchbase Oui Non Non MongoDB Oui Non Non Spring Data 2.0 Oui Non Oui Reactor IPC Non Non Oui WebFlux Non Oui Oui Android Spring
  85. RxJava RxJava 2 Reactor Retrofit Oui Oui Non RxAndroid Oui

    Oui Non Realm Oui Non Non Hystrix Oui Non Non Couchbase Oui Non Non MongoDB Oui Non Non Spring Data 2.0 Oui Non Oui Reactor IPC Non Non Oui WebFlux Non Oui Oui Android Spring
  86. RxJava RxJava 2 Reactor Retrofit Oui Oui Non RxAndroid Oui

    Oui Non Realm Oui Non Non Hystrix Oui Non Non Couchbase Oui Non Non MongoDB Oui Non Non Spring Data 2.0 Oui Non Oui Reactor IPC Non Non Oui WebFlux Non Oui Oui Android Spring genre pourquoi si tu as une stack spring se forcer a faire du rx2 si le support reactor est meilleur)?
  87. RxJava RxJava 2 Reactor Retrofit Oui Oui Non RxAndroid Oui

    Oui Non Realm Oui Non Non Hystrix Oui Non Non Couchbase Oui Non Non MongoDB Oui Non Non Spring Data 2.0 Oui Non Oui Reactor IPC Non Non Oui WebFlux Non Oui Oui Android Spring
  88. Merci pour votre attention On reste en contact ? [email protected]

    @dwursteisen http://blog.soat.fr RefCard RxJava 2 bientôt disponible !