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

Reactive System. What and How?

Reactive System. What and How?

Oleh Dokuka

August 19, 2017
Tweet

More Decks by Oleh Dokuka

Other Decks in Programming

Transcript

  1. Reactive System.
    What and How?
    by Oleh Dokuka

    View Slide

  2. About me
    2

    View Slide

  3. • JSE at Levi9
    About me
    2

    View Slide

  4. • JSE at Levi9
    • JEEConf Speaker
    About me
    2

    View Slide

  5. • JSE at Levi9
    • JEEConf Speaker
    • Spring fan
    About me
    2

    View Slide

  6. • JSE at Levi9
    • JEEConf Speaker
    • Spring fan
    • Reactivity preacher
    About me
    2

    View Slide

  7. • JSE at Levi9
    • JEEConf Speaker
    • Spring fan
    • Reactivity preacher
    /oleh.dokuka /OlegDokuka
    /OlehDokuka
    About me
    2

    View Slide

  8. 3
    Agenda

    View Slide

  9. 3
    • Reactive Approach
    Agenda

    View Slide

  10. 3
    • Reactive System
    • Reactive Approach
    Agenda

    View Slide

  11. 3
    • Reactive System
    • Reactive Programming
    • Reactive Approach
    Agenda

    View Slide

  12. 3
    • Reactive System
    • Reactive Programming
    • Reactive Approach
    Agenda
    • Reactive In Action

    View Slide

  13. Why Reactive?
    4

    View Slide

  14. 5

    View Slide

  15. 6

    View Slide

  16. 7

    View Slide

  17. Responsive?
    8

    View Slide

  18. 9
    Responsive

    View Slide

  19. 9
    Responsive

    View Slide

  20. 10
    Responsive
    10

    View Slide

  21. 10
    Responsive
    Elastic
    10

    View Slide

  22. 10
    Responsive
    Elastic
    10

    View Slide

  23. Responsive
    Elastic

    View Slide

  24. Responsive
    Elastic Resilient

    View Slide

  25. Responsive
    Elastic Resilient

    View Slide

  26. 12
    Responsive
    Elastic Resilient
    12

    View Slide

  27. 12
    Responsive
    Elastic Resilient
    12

    View Slide

  28. 13
    Responsive
    Elastic Resilient

    View Slide

  29. 13
    Responsive
    Elastic Resilient
    Message Driven

    View Slide

  30. 13
    Responsive
    Elastic Resilient
    Message Driven

    View Slide

  31. 13
    Responsive
    Elastic Resilient
    Message Driven

    View Slide

  32. 13
    Responsive
    Elastic Resilient
    Message Driven

    View Slide

  33. 14
    Responsive
    Elastic Resilient
    Message Driven

    View Slide

  34. Reactive Manifesto
    15
    http://www.reactivemanifesto.org/

    View Slide

  35. Common Vocabulary
    16

    View Slide

  36. Reactive System
    17

    View Slide

  37. Architecture
    18

    View Slide

  38. 19
    Message Driven

    View Slide

  39. Reactive Programming
    20

    View Slide

  40. Reactive Programming
    !=
    Reactive System
    21

    View Slide

  41. Reactive Programming
    Evolution
    22

    View Slide

  42. Observer Pattern
    Event Listening
    23

    View Slide

  43. 24

    View Slide

  44. 24

    View Slide

  45. 25

    View Slide

  46. 25

    View Slide

  47. 26

    View Slide

  48. 26

    View Slide

  49. new EventHandler() {
    void onEvent(Event event) {
    //do stuff
    }
    }
    27

    View Slide

  50. eventSource.setHandler(
    new EventHandler() {
    void onEvent(Event event) {
    //do stuff
    }
    }
    );
    28

    View Slide

  51. anotherEventSource.setHandler(
    new EventHandler() {
    void onEvent(Event event) {
    eventSource.setHandler(
    new EventHandler() {
    void onEvent(Event event) {
    //do stuff
    }
    }
    );
    }
    }
    ); 29

    View Slide

  52. Pyramid of Doom
    30

    View Slide

  53. Async operation?
    31

    View Slide

  54. Framework’s Way
    32

    View Slide

  55. @Component EventHandler() {
    @EventListener
    void onEvent(Event event) {
    //do stuff
    }
    }
    33

    View Slide

  56. @Component EventHandler() {
    @EventListener
    void onEvent(Event event) {
    //do stuff
    }
    }
    34

    View Slide

  57. No Clear Flow
    35

    View Slide

  58. Reactive Extension
    36

    View Slide

  59. Rx.Net
    37

    View Slide

  60. 38
    DataSource Subscriber

    View Slide

  61. 38
    DataSource
    Observable
    Subscriber

    View Slide

  62. 39
    Observable
    DataSource Subscriber

    View Slide

  63. 39
    Observable
    DataSource
    Observer
    Subscriber

    View Slide

  64. 40
    Observable
    DataSource Subscriber
    Observer

    View Slide

  65. 40
    Observable
    DataSource Subscriber
    onNext()
    onError()
    onComplete()
    Observer

    View Slide

  66. 40
    Observable
    DataSource Subscriber
    onNext()
    onError()
    onComplete()
    Observer

    View Slide

  67. 41
    onNext()
    onError()
    onComplete()
    Observable Observer
    Subscriber
    DataSource

    View Slide

  68. 41
    onNext()
    onError()
    onComplete()
    Observable Observer
    Subscriber
    DataSource
    Observer
    Transform
    onNext()
    onError()
    onComplete()

    View Slide

  69. 41
    onNext()
    onError()
    onComplete()
    Observable Observer
    Subscriber
    DataSource
    Observer
    Transform
    onNext()
    onError()
    onComplete()

    View Slide

  70. Observer
    Transform
    42
    Observable Observer
    Subscriber
    DataSource
    onNext()
    onError()
    onComplete()
    onNext()
    onError()
    onComplete()

    View Slide

  71. IObservable
    43

    View Slide

  72. IObserver
    44

    View Slide

  73. public interface IObserver
    {
    // Notifies the observer that
    // the source has finished sending messages.
    void OnCompleted();
    // Notifies the observer about any
    // exception or error.
    void OnError(Exception error);
    // Pushes the next data value from
    // the source to the observer.
    void OnNext(T value);
    }
    45

    View Slide

  74. public interface IObserver
    {
    // Notifies the observer that
    // the source has finished sending messages.
    void OnCompleted();
    // Notifies the observer about any
    // exception or error.
    void OnError(Exception error);
    // Pushes the next data value from
    // the source to the observer.
    void OnNext(T value);
    }
    46

    View Slide

  75. public interface IObserver
    {
    // Notifies the observer that
    // the source has finished sending messages.
    void OnCompleted();
    // Notifies the observer about any
    // exception or error.
    void OnError(Exception error);
    // Pushes the next data value from
    // the source to the observer.
    void OnNext(T value);
    }
    47

    View Slide

  76. public interface IObserver
    {
    // Notifies the observer that
    // the source has finished sending messages.
    void OnCompleted();
    // Notifies the observer about any
    // exception or error.
    void OnError(Exception error);
    // Pushes the next data value from
    // the source to the observer.
    void OnNext(T value);
    }
    48

    View Slide

  77. API
    Transformations, Operations, etc.
    49

    View Slide

  78. API
    .just()
    .from()
    .defer()
    .map()
    .filter()
    .flatMap()
    etc.
    50

    View Slide

  79. Benefit
    51

    View Slide

  80. observable.businessFunction()
    .map(mapFunction())
    .filter(filterFunction())
    .map(mapFunction())
    .doOnNext(someAction())
    .subscribe()
    52

    View Slide

  81. Clear flow!
    Looks imperative, but actually async non-blocking
    processing of events
    53

    View Slide

  82. Order Processing Flow
    54

    View Slide

  83. RxJava
    Successful Story of Copy/Paste
    55

    View Slide

  84. Observable
    56

    View Slide

  85. class Observable {
    ...
    static Observable from(T... items)
    static Observable range(...)
    static Observable just(T value)
    ...
    }
    57

    View Slide

  86. class Observable {
    ...
    Observable map(...)
    Observable filter(...)
    Observable flatMap(...)
    ...
    }
    58

    View Slide

  87. Observer
    59

    View Slide

  88. interface Observer {
    void onCompleted();
    void onError(Throwable e);
    void onNext(T args);
    }
    60

    View Slide

  89. Subscription
    61

    View Slide

  90. class Observable {
    ...
    Subscription subscribe(Observer observer){
    ...
    }
    ...
    }
    62

    View Slide

  91. class Observable {
    ...
    Subscription subscribe(Observer observer){
    ...
    }
    ...
    }
    63

    View Slide

  92. class Observable {
    ...
    Subscription subscribe(Observer observer){
    ...
    }
    ...
    }
    64

    View Slide

  93. class Observable {
    ...
    Subscription subscribe(Observer observer){
    ...
    }
    ...
    }
    65

    View Slide

  94. Flow Examples
    66

    View Slide

  95. Source Creation
    67

    View Slide

  96. Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    68

    View Slide

  97. Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    a
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    68

    View Slide

  98. .just( )
    a
    a
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    69

    View Slide

  99. .just( )
    a
    a
    onNext()
    onError()
    onComplete()
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    69

    View Slide

  100. .just( )
    onNext()
    onError()
    onComplete()
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    a
    70

    View Slide

  101. .just( )
    .just( )
    onNext()
    onNext()
    onError()
    onComplete()
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    a
    70

    View Slide

  102. onNext()
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    a
    onError()
    onComplete()
    71

    View Slide

  103. onNext()
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    onNext()
    .just( )
    onError()
    onComplete()
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    onComplete()
    71

    View Slide

  104. onComplete()
    onNext()
    .just( )
    onError()
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    72

    View Slide

  105. onComplete()
    onNext()
    .just( )
    onError()
    onComplete()
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    72

    View Slide

  106. Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    onNext()
    Observable
    .just("a")
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    onError()
    onComplete()
    onComplete()
    onComplete()
    73

    View Slide

  107. Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    74

    View Slide

  108. Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from(asList( ))
    a b
    74

    View Slide

  109. 75
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from(asList( ))
    a b

    View Slide

  110. 75
    onNext()
    onError()
    onComplete()
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from(asList( ))
    a b

    View Slide

  111. .from(asList( ))
    76
    onNext()
    onError()
    onComplete()
    a
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    b

    View Slide

  112. .from(asList( ))
    .from(asList( ))
    76
    onNext()
    onError()
    onComplete()
    onNext()
    a
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    b

    View Slide

  113. onNext()
    onComplete()
    .from(asList( ))
    onError()
    .from(asList( ))
    77
    onError()
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    a b

    View Slide

  114. onComplete()
    onNext()
    onComplete()
    onNext()
    .from(asList( ))
    onError()
    .from(asList( ))
    77
    onError()
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  115. onNext()
    onComplete()
    onNext()
    .from(asList( ))
    onComplete()
    onError()
    .from(asList( ))
    78
    onError()
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  116. onNext()
    onComplete()
    onNext()
    .from(asList( ))
    onComplete()
    onError()
    .from(asList( ))
    78
    onError()
    onComplete()
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  117. .from(asList( ))
    onComplete()
    onError()
    79
    onNext()
    Observable
    .from(asList("a","b"))
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  118. 80
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  119. 80
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .defer()
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  120. Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    81
    .defer()

    View Slide

  121. Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    81
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .defer()
    onNext()
    onError()
    onComplete()

    View Slide

  122. Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    onNext()
    onError()
    onComplete()
    82
    .defer()

    View Slide

  123. Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    onNext()
    onError()
    onComplete()
    82
    .just( )
    a b
    .defer()
    .defer()

    View Slide

  124. .just( )
    onNext()
    onError()
    onComplete()
    83
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    a b
    .defer()

    View Slide

  125. .just( )
    onNext()
    onNext()
    onError()
    onComplete()
    83
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    a b
    .defer()
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  126. onNext()
    onError()
    onComplete()
    84
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    .defer()
    a b

    View Slide

  127. onNext()
    onNext()
    onError()
    onComplete()
    onComplete()
    84
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    .defer()
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  128. onComplete()
    onNext()
    onError()
    85
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    .defer()

    View Slide

  129. onComplete()
    onNext()
    onError()
    onComplete()
    85
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    .defer()
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  130. onNext()
    onError()
    onComplete()
    onComplete()
    onComplete()
    86
    Observable
    .defer(() ->
    just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    .defer()

    View Slide

  131. Transformations
    87

    View Slide

  132. 88
    .map(…)
    .map()

    View Slide

  133. 88
    .map(…)
    .map()

    View Slide

  134. 89
    .filter(…)
    .filter()

    View Slide

  135. 89
    .filter(…)
    .filter()

    View Slide

  136. 90
    .flatMap(…)
    .flatMap()

    View Slide

  137. 90
    .flatMap(…)
    .flatMap()

    View Slide

  138. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    91

    View Slide

  139. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    91
    .map()
    .filter()
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()

    View Slide

  140. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    .filter()
    .map()
    92

    View Slide

  141. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    .filter()
    .map()
    92

    View Slide

  142. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    .map()
    .filter()
    93

    View Slide

  143. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    .map()
    .filter()
    93

    View Slide

  144. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    .map()
    94
    .filter()

    View Slide

  145. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    .map()
    94
    .filter()

    View Slide

  146. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .subscribe()
    .map()
    .filter()
    95

    View Slide

  147. Thread Manipulation
    96

    View Slide

  148. Thread A
    Thread Main
    .observeOn(…)
    .observeOn()
    97

    View Slide

  149. Thread A
    Thread Main
    .observeOn(…)
    .observeOn()
    97

    View Slide

  150. 98
    .subscribeOn()
    Thread Main
    Thread A
    .subscribeOn(…)

    View Slide

  151. 98
    .subscribeOn()
    Thread Main
    Thread A
    .subscribeOn(…)

    View Slide

  152. 98
    .subscribeOn()
    Thread Main
    Thread A
    .subscribeOn(…)

    View Slide

  153. Quiz
    99

    View Slide

  154. Observable
    .just(1, 20, 300, 4000)
    .map(Object::toString)
    .filter(v -> v.length() > 3)
    100
    Output?

    View Slide

  155. Observable
    .just(1, 20, 300, 4000)
    .map(Object::toString)
    .filter(v -> v.length() > 3)
    .subscribe(System.out::println)
    Output?
    101

    View Slide

  156. Output?
    102
    Observable
    .just(1, 20, 300, 4000)
    .map(Object::toString)
    .filter(v -> v.length() > 3)
    .subscribe(System.out::println)

    View Slide

  157. Hot vs. Cold
    Observables
    103

    View Slide

  158. Cold
    104

    View Slide

  159. .from( )
    4
    3
    2
    1
    Observable
    .just(1, 2, 3, 4)
    1 2 3 4
    105

    View Slide

  160. .from( )
    4
    3
    2
    1
    Observable
    .just(1, 2, 3, 4)
    1
    2
    3
    4
    .subscribe()
    105

    View Slide

  161. .from( )
    4
    3
    2
    1
    Observable
    .just(1, 2, 3, 4)
    1
    2
    3
    4
    1 2 3 4
    .subscribe()
    106

    View Slide

  162. .from( )
    4
    3
    2
    1
    Observable
    .just(1, 2, 3, 4)
    1
    2
    3
    4 1
    2
    3
    4
    .subscribe()
    .subscribe()
    106

    View Slide

  163. .from( )
    4
    3
    2
    1
    Observable
    .just(1, 2, 3, 4)
    1
    2
    3
    4 1
    2
    3
    4
    .subscribe()
    .subscribe()
    107

    View Slide

  164. Hot
    108

    View Slide

  165. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    109

    View Slide

  166. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .map()
    .filter()
    109

    View Slide

  167. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .filter()
    .map()
    110

    View Slide

  168. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .filter()
    .map()
    110

    View Slide

  169. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .map()
    .filter()
    111

    View Slide

  170. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .map()
    .filter()
    111

    View Slide

  171. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .map()
    .filter()
    112

    View Slide

  172. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .map()
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .filter()
    112

    View Slide

  173. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .map()
    .filter()
    113

    View Slide

  174. externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .map()
    .filter()
    114

    View Slide

  175. .subscribe()
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .map()
    .filter()
    114

    View Slide

  176. .subscribe()
    externalService
    .messagesStream()
    .map(...)
    .filter(...)
    .map()
    .filter()
    115

    View Slide

  177. RxJava Cons
    116

    View Slide

  178. RxJava Cons
    116

    View Slide

  179. RxJava Cons
    • Not easy to understand
    • Unexpected behaviors
    • Complicated extensibility
    • No backpressure
    117

    View Slide

  180. 118

    View Slide

  181. Problem
    119

    View Slide

  182. Reactive Streams
    120

    View Slide

  183. Purpose?
    121

    View Slide

  184. Common API
    122

    View Slide

  185. 123
    Publisher

    View Slide

  186. 123
    Publisher
    Observable
    like

    View Slide

  187. 124
    Subscriber

    View Slide

  188. 124
    Subscriber
    Observer
    like

    View Slide

  189. 125
    public interface Publisher {
    public void subscribe(
    Subscriber super T> s
    );
    }

    View Slide

  190. 126
    .publish( )
    a Publisher

    View Slide

  191. 126
    .publish( )
    a
    Subscriber
    .subscribe()
    Publisher
    Publisher

    View Slide

  192. 127
    Subscription

    View Slide

  193. 128
    public interface Subscriber {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
    }

    View Slide

  194. 128
    public interface Subscriber {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
    }
    public interface Subscriber {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
    }

    View Slide

  195. public interface Subscription {
    public void request(long n);
    public void cancel();
    }
    129

    View Slide

  196. public interface Subscription {
    public void request(long n);
    public void cancel();
    }
    129
    public interface Subscription {
    public void request(long n);
    public void cancel();
    }

    View Slide

  197. Subscriber {
    void onSubscribe(Subscription s){
    s.request(1);
    }

    } 130
    .publish( )
    a
    .subscribe()
    Publisher

    View Slide

  198. Subscriber {
    void onSubscribe(Subscription s){
    s.request(1);
    }

    }
    Subscriber {
    void onSubscribe(Subscription s){
    s.request(1);
    }

    } 130
    .publish( )
    a
    .subscribe()
    Publisher

    View Slide

  199. Publisher
    Subscriber {
    void onSubscribe(Subscription s){
    s.request(1);
    }

    }
    Subscriber {
    void onSubscribe(Subscription s){
    s.request(1);
    }

    } 131
    .publish( )
    .subscribe()
    a

    View Slide

  200. Publisher
    Subscriber {
    void onSubscribe(Subscription s){
    s.request(1);
    }

    }
    Subscriber {
    void onSubscribe(Subscription s){
    s.request(1);
    }

    } 131
    .publish( )
    .subscribe()
    Publisher
    a

    View Slide

  201. Publisher
    Subscriber {
    void onSubscribe(Subscription s){
    s.request(1);
    }

    }
    Subscriber {
    void onSubscribe(Subscription s){
    s.request(1);
    }

    } 131
    .publish( )
    .subscribe()
    Publisher
    a

    View Slide

  202. Backpressure Support
    132

    View Slide

  203. 133
    Processor

    View Slide

  204. 134
    interface Processor
    extends
    Subscriber,
    Publisher {
    }

    View Slide

  205. 135
    .publish( )
    .subscribe()
    Publisher
    a
    Subscriber

    View Slide

  206. 135
    .publish( )
    .subscribe()
    Publisher
    a
    .process() Processor
    Subscriber
    Publisher
    Subscriber

    View Slide

  207. Processor
    .publish( )
    136
    .subscribe()
    Publisher
    a
    .process()
    Subscriber

    View Slide

  208. Processor
    Processor {
    s.request(1);
    }
    Processor {
    s.request(1);
    }
    .publish( )
    136
    .subscribe()
    Publisher
    a
    .process()
    Subscriber

    View Slide

  209. Processor
    Processor {
    s.request(1);
    }
    .publish( )
    b
    .process()
    137
    .subscribe()
    Publisher
    a
    Subscriber

    View Slide

  210. Processor
    Processor {
    s.request(1);
    }
    .publish( )
    b
    .process()
    137
    .subscribe()
    Publisher
    Subscriber
    a

    View Slide

  211. Processor {
    s.request(1);
    }
    .publish( )
    b
    .process()
    138
    .subscribe()
    Publisher
    Subscriber
    a

    View Slide

  212. Processor {
    s.request(1);
    }
    Processor {
    s.request(1);
    }
    Processor {
    s.request(1);
    }
    .publish( )
    b
    .process()
    138
    .subscribe()
    Publisher
    Subscriber
    a

    View Slide

  213. Processor
    Processor {
    s.request(1);
    }
    .publish( )
    .process()
    139
    .subscribe()
    Publisher
    Subscriber
    a
    b

    View Slide

  214. Processor
    Processor {
    s.request(1);
    }
    .publish( )
    .process()
    139
    .subscribe()
    Publisher
    Subscriber
    a
    b

    View Slide

  215. Subscriber
    Processor
    140
    .publish( )
    .subscribe()
    Publisher
    .process() Processor
    b a

    View Slide

  216. Subscriber
    Subscriber {
    s.request(2);
    }
    Processor
    140
    .publish( )
    .subscribe()
    Publisher
    .process() Processor
    b a

    View Slide

  217. Subscriber
    Processor
    141
    .publish( )
    .subscribe()
    Publisher
    .process() Processor
    Subscriber
    b a

    View Slide

  218. Subscriber
    Processor
    141
    .publish( )
    .subscribe()
    Publisher
    .process() Processor
    Subscriber
    b a Subscriber

    View Slide

  219. Subscriber
    Subscriber
    Processor
    142
    .publish( )
    .subscribe()
    Publisher
    .process() Processor
    b a

    View Slide

  220. Project Reactor
    143

    View Slide

  221. by
    144

    View Slide

  222. RxJava-like API
    145

    View Slide

  223. Benefit
    146

    View Slide

  224. Benefit
    146

    View Slide

  225. Reactive Types
    147

    View Slide

  226. Flux
    148

    View Slide

  227. Flux
    148
    Observable
    like

    View Slide

  228. 149
    abstract class Flux implements Publisher
    {
    ...
    static Flux from(...)
    static Flux range(...)
    static Flux just(T data)
    ...
    }

    View Slide

  229. 150
    abstract class Flux implements Publisher
    {
    ...
    Flux map(...)
    Flux filter(...)
    Flux flatMap(...)
    ...
    }

    View Slide

  230. Mono
    151

    View Slide

  231. Mono
    151
    ?????????????
    like

    View Slide

  232. 152

    View Slide

  233. Mono
    153
    Observable
    like

    View Slide

  234. BUT!
    154

    View Slide

  235. For Zero or One
    element
    155

    View Slide

  236. 156
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .just( )
    a b

    View Slide

  237. 157
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .just( )
    a b

    View Slide

  238. 157
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .just( )
    a b
    onNext()
    onError()
    onComplete()
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  239. .from( ____
    )
    .just( )
    a b
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    158
    onNext()
    onError()
    onComplete()

    View Slide

  240. .from( ____
    )
    .just( )
    a b
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    158
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .just( )
    a b
    onNext()
    onError()
    onComplete()

    View Slide

  241. Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .just( )
    a b
    159
    .from( ____
    )
    .just( )
    b
    onNext()
    onError()
    onComplete()
    a

    View Slide

  242. Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .just( )
    a b
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    159
    .from( ____
    )
    .just( )
    b
    onNext()
    onError()
    onComplete()
    onNext()
    a

    View Slide

  243. Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .from( ____
    )
    .just( )
    a b
    160
    .just( )
    onNext()
    onError()
    onComplete()
    a
    b

    View Slide

  244. Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .from( ____
    )
    .from( ____
    )
    .just( )
    a b
    160
    .just( )
    onNext()
    onError()
    onComplete()
    a
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )
    b

    View Slide

  245. Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .from( ____
    )
    .from( ____
    )
    .just( )
    a b
    160
    .just( )
    onNext()
    onError()
    onComplete()
    a
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .just( )

    View Slide

  246. Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .from( ____
    )
    .just( )
    a b
    161
    .just( )
    onNext()
    onError()
    onComplete()
    a
    .just( )

    View Slide

  247. Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )
    .from( ____
    )
    .from( ____
    )
    .just( )
    a b
    161
    .just( )
    onNext()
    onError()
    onComplete()
    a
    .just( )
    onComplete()
    Mono.from(
    Flux.just("a", "b")
    )
    .subscribe(
    onNext(),
    onError(),
    onComplete()
    )

    View Slide

  248. API
    Operations, Transformations, etc.
    162

    View Slide

  249. API
    .merge() & .mergeWith()
    .zip() & .zipWith()
    .publish()
    etc.
    163

    View Slide

  250. .merge()
    .merge(…)
    164

    View Slide

  251. .merge()
    .merge(…)
    164

    View Slide

  252. 165
    Flux.merge(
    Flux.just("a"),
    Flux.just("b")
    )
    .mergeWith(Flux.just("c"));

    View Slide

  253. .zip()
    .zip(…)
    166

    View Slide

  254. .zip()
    .zip(…)
    166

    View Slide

  255. .zip()
    .zip(…)
    166

    View Slide

  256. .zip(…)
    167
    .zip()

    View Slide

  257. .zip(…)
    167
    .zip()

    View Slide

  258. 168
    Flux.zip(
    Flux.just("a"),
    Flux.just("b"),
    (a, b) -> a + b
    )
    .zipWith(Flux.just("c"),
    (ab, c) -> ab + c);

    View Slide

  259. 169
    .from()

    View Slide

  260. 169
    .from()
    static Flux from(Publisher source)
    static Mono from(Publisher source)

    View Slide

  261. 170
    Flux
    .from(externalPublisher())
    .from()

    View Slide

  262. 171
    Mono
    .from(externalPublisher())
    .from()

    View Slide

  263. 172
    .fromStream()

    View Slide

  264. 172
    .fromStream()
    static Flux fromStream(Stream s)

    View Slide

  265. 173
    Flux.fromStream(
    Stream.of("a", "b")
    )

    View Slide

  266. Backpressure Support
    174
    .onBackpressureBuffer()
    .onBackpressureDrop()
    .onBackpressureLatest()
    etc.

    View Slide

  267. Summary
    1st Part
    175

    View Slide

  268. Reactivity in Action
    176

    View Slide

  269. Action Plan
    Refactoring
    177

    View Slide

  270. Chat Application
    178

    View Slide

  271. Functionality
    • Gitter Chat Communication
    • Messaging Statistics
    179

    View Slide

  272. https://goo.gl/XcnEnr
    180

    View Slide

  273. Demo
    181

    View Slide

  274. Toolkit
    • Spring Framework 4.x
    • Spring MVC
    • Spring Data JPA
    • Spring Boot 1.5.x
    182

    View Slide

  275. Architecture
    183

    View Slide

  276. 184

    View Slide

  277. User Client
    184

    View Slide

  278. Gitter Service
    184

    View Slide

  279. Whole Application
    184

    View Slide

  280. Controllers Layer
    184

    View Slide

  281. Service Layer
    184

    View Slide

  282. DB Layer
    184

    View Slide

  283. Controllers
    185

    View Slide

  284. Thymeleaf View
    186

    View Slide

  285. REST Resources
    187

    View Slide

  286. Services
    188

    View Slide

  287. External Chats SPI
    189

    View Slide

  288. Domain Services
    190

    View Slide

  289. Gitter Integration
    191

    View Slide

  290. Service
    Implementations
    192

    View Slide

  291. Persistence
    193

    View Slide

  292. Database Model
    194

    View Slide

  293. Existing Flow
    195

    View Slide

  294. 196

    View Slide

  295. 196

    View Slide

  296. 197

    View Slide

  297. 197

    View Slide

  298. 198

    View Slide

  299. 198

    View Slide

  300. 199

    View Slide

  301. 199

    View Slide

  302. Problems
    200

    View Slide

  303. Problems
    • Pulling model
    201

    View Slide

  304. 202

    View Slide

  305. 202

    View Slide

  306. Problems
    • Pulling model
    • Blocking I/O
    203

    View Slide

  307. Solutions
    204

    View Slide

  308. Reactive Manifesto
    205

    View Slide

  309. 206

    View Slide

  310. 206

    View Slide

  311. 207

    View Slide

  312. Async Messaging
    Push Model
    207

    View Slide

  313. Gitter
    Streaming API
    208

    View Slide

  314. 209

    View Slide

  315. 209

    View Slide

  316. 210

    View Slide

  317. 210

    View Slide

  318. 211

    View Slide

  319. Async Messaging
    Elasticity
    211

    View Slide

  320. Reactive DB Driver
    212

    View Slide

  321. 213

    View Slide

  322. 213

    View Slide

  323. 214

    View Slide

  324. 214

    View Slide

  325. 215

    View Slide

  326. Async Messaging
    Push Model
    215

    View Slide

  327. WebSocket
    216

    View Slide

  328. 217

    View Slide

  329. 217

    View Slide

  330. One Solution for
    Everything
    218

    View Slide

  331. Spring 5 :)
    219

    View Slide

  332. Painless Replacement
    220

    View Slide

  333. Reactive Stack (WebFlux)
    @Controller, @RequestMapping,…
    Spring MVC
    Servlet API
    Servlet Container
    Spring Web Reactive
    Reactive HTTP
    Servlet, Netty, Undertow
    221

    View Slide

  334. @RestController
    @RequestMapping("/api/v1/statistics")
    public class StatisticResource {
    private final StatisticService statisticService;
    @Autowired
    public StatisticResource(
    StatisticService statisticService) {
    this.statisticService = statisticService;
    }
    @GetMapping("/users")
    public List getUsersStatistic() {
    return statisticService.getUsersStatistic();
    }
    }
    222

    View Slide

  335. @RestController
    @RequestMapping("/api/v1/statistics")
    public class StatisticResource {
    private final StatisticService statisticService;
    @Autowired
    public StatisticResource(
    StatisticService statisticService) {
    this.statisticService = statisticService;
    }
    @GetMapping("/users")
    public List getUsersStatistic() {
    return statisticService.getUsersStatistic();
    }
    }
    223

    View Slide

  336. @RestController
    @RequestMapping("/api/v1/statistics")
    public class StatisticResource {
    private final StatisticService statisticService;
    @Autowired
    public StatisticResource(
    StatisticService statisticService) {
    this.statisticService = statisticService;
    }
    @GetMapping("/users")
    public Flux getUsersStatistic() {
    return Flux.fromIterable(statisticService
    .getUsersStatistic());
    }
    224

    View Slide

  337. @RestController
    @RequestMapping("/api/v1/statistics")
    public class StatisticResource {
    private final StatisticService statisticService;
    @Autowired
    public StatisticResource(
    StatisticService statisticService) {
    this.statisticService = statisticService;
    }
    @GetMapping("/users")
    public Flux getUsersStatistic() {
    return Flux.fromIterable(statisticService
    .getUsersStatistic());
    }
    225

    View Slide

  338. 226

    View Slide

  339. 226

    View Slide

  340. 227

    View Slide

  341. Why Netty?
    228

    View Slide

  342. Asynchronous
    event-driven framework
    229

    View Slide

  343. New
    Reactive Architecture
    230

    View Slide

  344. Data Base Connection Pipe
    Gitter Connection Pipe
    231
    Client Connection Pipe

    View Slide

  345. Data Base Connection Pipe
    Gitter Connection Pipe
    231
    Client Connection Pipe

    View Slide

  346. Refactoring Steps
    232

    View Slide

  347. 1. Update to Spring 5
    2. Reactive Interfaces
    3. Reactive Services
    4. Reactive Endpoints
    233

    View Slide

  348. https://goo.gl/yxAJGI
    234

    View Slide

  349. Update To Spring 5
    235

    View Slide

  350. Code Session
    236

    View Slide

  351. Reactive Interfaces
    237

    View Slide

  352. Reactive DB Access
    ReactiveCrudRepository
    238

    View Slide

  353. interface ReactiveCrudRepository extends Repository
    Mono save(S entity);
    Flux saveAll(Iterable entities);
    Flux saveAll(Publisher entityStream);
    Mono findById(ID id);
    Mono findById(Mono id);
    Mono existsById(ID id);
    Mono existsById(Mono id);
    Flux findAll();
    Flux findAllById(Iterable ids);
    Flux findAllById(Publisher idStream);
    Mono count();
    Mono deleteById(ID id);
    Mono delete(T entity);
    Mono deleteAll(Iterable extends T> entities);
    Mono deleteAll(Publisher extends T> entityStream);
    Mono deleteAll();
    } 239

    View Slide

  354. interface ReactiveCrudRepository extends Repository
    Mono save(S entity);
    Flux saveAll(Iterable entities);
    Flux saveAll(Publisher entityStream);
    Mono findById(ID id);
    Mono findById(Mono id);
    Mono existsById(ID id);
    Mono existsById(Mono id);
    Flux findAll();
    Flux findAllById(Iterable ids);
    Flux findAllById(Publisher idStream);
    Mono count();
    Mono deleteById(ID id);
    Mono delete(T entity);
    Mono deleteAll(Iterable extends T> entities);
    Mono deleteAll(Publisher extends T> entityStream);
    Mono deleteAll();
    } 240

    View Slide

  355. Code Session
    241

    View Slide

  356. Reactive Services
    242

    View Slide

  357. Gitter Service
    243

    View Slide

  358. Reactive WebClient
    Out-of-the-box
    244

    View Slide

  359. public interface WebClient {
    UriSpec> get();
    //omitted...
    static WebClient create() {
    return new DefaultWebClientBuilder().build();
    }
    interface RequestHeadersSpec> {
    //omitted...
    Mono exchange();
    //omitted...
    }
    interface ResponseSpec {
    Mono bodyToMono(Class bodyType);
    Flux bodyToFlux(Class elementType);
    Mono> toEntity(Class bodyType);
    Mono>> toEntityList(Class element
    }
    } 245

    View Slide

  360. public interface WebClient {
    UriSpec> get();
    //omitted...
    static WebClient create() {
    return new DefaultWebClientBuilder().build();
    }
    interface RequestHeadersSpec> {
    //omitted...
    Mono exchange();
    //omitted...
    }
    interface ResponseSpec {
    Mono bodyToMono(Class bodyType);
    Flux bodyToFlux(Class elementType);
    Mono> toEntity(Class bodyType);
    Mono>> toEntityList(Class element
    }
    } 246

    View Slide

  361. 247

    View Slide

  362. 247

    View Slide

  363. Code Session
    248

    View Slide

  364. @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    249

    View Slide

  365. @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    249
    .getMS()
    .getLM()
    .retry()
    cache

    View Slide

  366. 250
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    .getMS()
    .getLM()
    .retry()
    cache

    View Slide

  367. 250
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    .getMS()
    .getLM()
    .retry()
    cache

    View Slide

  368. .getMS()
    .getLM()
    .retry()
    cache
    251
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  369. .getMS()
    .getLM()
    .retry()
    cache
    251
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  370. .getLM() .getMS()
    .retry()
    cache
    252
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  371. .getLM() .getMS()
    .retry()
    cache
    252
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  372. .getMS()
    .getLM()
    .retry()
    cache
    253
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  373. .getMS()
    .getLM()
    .retry()
    cache
    253
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    .getLM()

    View Slide

  374. .getMS()
    .getLM()
    .retry()
    cache
    254
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  375. .getMS()
    .getLM()
    .retry()
    cache
    254
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  376. .getMS()
    .getLM()
    .retry()
    cache
    255
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  377. .getMS()
    .getLM()
    .retry()
    cache
    255
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  378. .getMS()
    .getLM()
    .retry()
    cache
    256
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  379. .getMS()
    .getLM()
    .retry()
    cache
    256
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  380. .getMS()
    .getLM()
    .retry()
    cache
    257
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  381. .getMS()
    .getLM()
    .retry()
    cache
    257
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  382. 258
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    .getMS()
    .getLM()
    .retry()
    cache

    View Slide

  383. …subscribe();
    258
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    .getMS()
    .getLM()
    .retry()
    cache
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  384. …subscribe();
    258
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    .getMS()
    .getLM()
    .retry()
    cache
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }

    View Slide

  385. …subscribe();
    259
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    .getMS()
    .getLM()
    .retry()
    cache

    View Slide

  386. @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    …subscribe();
    260
    .getMS()
    .getLM()
    .retry()
    cache

    View Slide

  387. @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    …subscribe();
    260
    .getMS()
    .getLM()
    .retry()
    cache
    .getMS()
    .retry()

    View Slide

  388. @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    …subscribe();
    261
    .getMS()
    .getLM()
    .retry()
    cache

    View Slide

  389. @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    …subscribe();
    261
    .getMS()
    .getLM()
    .retry()
    cache
    …subscribe();

    View Slide

  390. @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    …subscribe();
    261
    .getMS()
    .getLM()
    .retry()
    cache
    …subscribe();

    View Slide

  391. …subscribe();
    262
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    .getMS()
    .getLM()
    .retry()
    cache
    @Autowired
    public GitterService(
    GitterClient gitterClient
    ) {
    gas = Flux.merge(
    getLatestMessages(),
    getMessagesStream(null)
    )
    .retryWhen(...)
    .replay(30)
    .autoConnect(0);
    }
    …subscribe();

    View Slide

  392. Message Service
    263

    View Slide

  393. 264

    View Slide

  394. 264

    View Slide

  395. Code Session
    265

    View Slide

  396. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    ApplicationContext context
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    } 266

    View Slide

  397. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    267

    View Slide

  398. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    268

    View Slide

  399. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    268

    View Slide

  400. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    269

    View Slide

  401. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    269

    View Slide

  402. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    270

    View Slide

  403. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    271

    View Slide

  404. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    271

    View Slide

  405. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    272

    View Slide

  406. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    272

    View Slide

  407. @Autowired
    public DefaultMessageService(
    MessageRepository messageRepository,
    ChatService chatClient,
    MessageBroker messageBroker
    ) {
    this.chatClient = chatClient;
    chatClient.stream()
    .transform(MessageMapper::toDomainUnits)
    .transform(messageRepository::saveAll)
    .subscribe()
    messageBroker.createChannel(
    "statisticChanged",
    saved.materialize()
    );
    }
    .transform()
    273

    View Slide

  408. @Override
    public Flux latest() {
    return chatClient.stream()
    .transform(MessageMapper
    ::toViewModelUnits
    );
    }
    @Override
    public Flux latest() {
    return chatClient.stream()
    .transform(MessageMapper
    ::toViewModelUnits
    );
    }
    @Override
    public Flux latest() {
    return chatClient.stream()
    .transform(MessageMapper
    ::toViewModelUnits
    );
    }
    .transform()
    274

    View Slide

  409. @Override
    public Flux latest() {
    return chatClient.stream()
    .transform(MessageMapper
    ::toViewModelUnits
    );
    }
    .transform()
    274

    View Slide

  410. Statistics Service
    275

    View Slide

  411. 276

    View Slide

  412. 276

    View Slide

  413. Code Session
    277

    View Slide

  414. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 278

    View Slide

  415. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 279

    View Slide

  416. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 279

    View Slide

  417. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 280

    View Slide

  418. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 280

    View Slide

  419. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 281

    View Slide

  420. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 282

    View Slide

  421. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 282

    View Slide

  422. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 283

    View Slide

  423. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    283

    View Slide

  424. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    284

    View Slide

  425. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    285

    View Slide

  426. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 285

    View Slide

  427. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…) 286

    View Slide

  428. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    286

    View Slide

  429. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    287

    View Slide

  430. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    287

    View Slide

  431. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    288

    View Slide

  432. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    289

    View Slide

  433. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    289

    View Slide

  434. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    290

    View Slide

  435. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    290

    View Slide

  436. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    291

    View Slide

  437. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    291

    View Slide

  438. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    292

    View Slide

  439. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    null
    292

    View Slide

  440. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .map(…)
    .defaultIfEmpty(…)
    .zip(…)
    293

    View Slide

  441. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    293

    View Slide

  442. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    294

    View Slide

  443. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    295

    View Slide

  444. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    295

    View Slide

  445. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    296

    View Slide

  446. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    296

    View Slide

  447. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    297

    View Slide

  448. private Mono doGetUserStatistic
    Mono topActiveUser =
    userRepository
    .findMostActive()
    .map(UserMapper::toViewModelUnits);
    Mono topMentionedUser =
    userRepository
    .findMostPopular()
    .map(UserMapper::toViewModelUnits);
    return Mono.zip(
    topActiveUser.defaultIfEmpty(EMPTY_USER),
    topMentionedUser.defaultIfEmpty(EMPTY_USER),
    UsersStatisticVM::new
    );
    }
    .defaultIfEmpty(…)
    .zip(…)
    .subscribe()
    297

    View Slide

  449. Reactive Endpoints
    298

    View Slide

  450. 299

    View Slide

  451. 299

    View Slide

  452. Reactive WebSocket
    Out-of-the-box
    300

    View Slide

  453. public interface WebSocketSession {
    String getId();
    HandshakeInfo getHandshakeInfo();
    DataBufferFactory bufferFactory();
    Flux receive();
    Mono send(Publisher messages);
    default Mono close() {
    return close(CloseStatus.NORMAL);
    }
    Mono close(CloseStatus status);
    WebSocketMessage textMessage(String payload);
    WebSocketMessage binaryMessage(
    Function payloadFactory);
    WebSocketMessage pingMessage(
    Function payloadFactory);
    WebSocketMessage pongMessage(
    Function payloadFactory);
    } 301

    View Slide

  454. public interface WebSocketSession {
    String getId();
    HandshakeInfo getHandshakeInfo();
    DataBufferFactory bufferFactory();
    Flux receive();
    Mono send(Publisher messages);
    default Mono close() {
    return close(CloseStatus.NORMAL);
    }
    Mono close(CloseStatus status);
    WebSocketMessage textMessage(String payload);
    WebSocketMessage binaryMessage(
    Function payloadFactory);
    WebSocketMessage pingMessage(
    Function payloadFactory);
    WebSocketMessage pongMessage(
    Function payloadFactory);
    } 302

    View Slide

  455. public interface WebSocketSession {
    String getId();
    HandshakeInfo getHandshakeInfo();
    DataBufferFactory bufferFactory();
    Flux receive();
    Mono send(Publisher messages);
    default Mono close() {
    return close(CloseStatus.NORMAL);
    }
    Mono close(CloseStatus status);
    WebSocketMessage textMessage(String payload);
    WebSocketMessage binaryMessage(
    Function payloadFactory);
    WebSocketMessage pingMessage(
    Function payloadFactory);
    WebSocketMessage pongMessage(
    Function payloadFactory);
    } 303

    View Slide

  456. Code Session
    304

    View Slide

  457. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    305

    View Slide

  458. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    306

    View Slide

  459. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    306

    View Slide

  460. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    307

    View Slide

  461. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    308

    View Slide

  462. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    308

    View Slide

  463. .merge()
    @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    309

    View Slide

  464. .merge()
    @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    309

    View Slide

  465. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    310

    View Slide

  466. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    310

    View Slide

  467. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    311

    View Slide

  468. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    312

    View Slide

  469. @Override
    public Publisher> handle(
    Publisher in
    ) {
    return Flux.merge(
    messageService.latest(),
    statisticService
    .usersStatisticStream()
    );
    }
    network
    .merge()
    312

    View Slide

  470. New
    Reactive Architecture
    313

    View Slide

  471. 314

    View Slide

  472. 314

    View Slide

  473. Demo
    315

    View Slide

  474. https://goo.gl/XcnEnr
    316

    View Slide

  475. Checklist
    • Message-Driven
    • Resilient
    • Responsive
    • Elastic
    317

    View Slide

  476. Checklist
    • Message-Driven
    • Resilient
    • Responsive
    • Elastic
    317

    View Slide

  477. Checklist
    • Message-Driven
    • Resilient
    • Responsive
    • Elastic
    317

    View Slide

  478. Checklist
    • Message-Driven
    • Resilient
    • Responsive
    • Elastic
    317

    View Slide

  479. Checklist
    • Message-Driven
    • Resilient
    • Responsive
    • Elastic
    317

    View Slide

  480. Summary
    318

    View Slide

  481. Q&A
    319

    View Slide

  482. Resources
    1. Why Reactive? [http://www.oreilly.com/programming/
    free/why-reactive.csp]
    2. Operator Fusion Part 1 [http://akarnokd.blogspot.com/
    2016/03/operator-fusion-part-1.html]
    3. Reactive Streams Specification [http://www.reactive-
    streams.org/]
    4. Learn Project Reactor [http://projectreactor.io/learn]
    320

    View Slide

  483. Thank you!
    321

    View Slide