‹#›© 2016 Pivotal Software, Inc. All rights reserved. ‹#›© 2017 Pivotal Software, Inc. All rights reserved. Spring Framework 5.0 Reactive Web Application Toshiaki Maki (@making) 2016-05-17 Java Day Tokyo 2017
© 2017 Pivotal Software, Inc. All rights reserved. Who am I ? • Toshiaki Maki (@making) https://blog.ik.am • Sr. Solutions Architect @Pivotal • Spring Framework 💖 • Cloud Foundry 💖 bit.ly/hajiboot2
© 2017 Pivotal Software, Inc. All rights reserved. Reactive???
© 2017 Pivotal Software, Inc. All rights reserved. Reactive??? "In a nutshell reactive programming is about non-blocking, event-driven applications that scale with a small number of threads with backpressure as a key ingredient that remains to ensure producers do not overwhelm consumers" - Rossen Stoyanchev
© 2017 Pivotal Software, Inc. All rights reserved. Sync / Blocking https://speakerdeck.com/simonbasle/reactor-3
© 2017 Pivotal Software, Inc. All rights reserved. Sync / Blocking https://speakerdeck.com/simonbasle/reactor-3 I/O main thread processing resumes
© 2017 Pivotal Software, Inc. All rights reserved. Sync / Blocking https://speakerdeck.com/simonbasle/reactor-3 I/O main thread processing resumes 😴 app does nothing
© 2017 Pivotal Software, Inc. All rights reserved. Async & Blocking https://speakerdeck.com/simonbasle/reactor-3
© 2017 Pivotal Software, Inc. All rights reserved. Async & Blocking https://speakerdeck.com/simonbasle/reactor-3 main thread wait & join
© 2017 Pivotal Software, Inc. All rights reserved. Async & Blocking https://speakerdeck.com/simonbasle/reactor-3 main thread wait & join complex new threads, costly
© 2017 Pivotal Software, Inc. All rights reserved. Async & Non-Blocking
© 2017 Pivotal Software, Inc. All rights reserved. Async & Non-Blocking https://speakerdeck.com/simonbasle/reactor-3 Event Loop chunks processing in non-blocking
© 2017 Pivotal Software, Inc. All rights reserved. Blocking + Thread pools (Servlet) HTTP request HTTP response 📖⏳ ⚙⏳ ✍⏳ Thread
© 2017 Pivotal Software, Inc. All rights reserved. Non-blocking and event-loop (Netty) IO Selector Thread Worker Threads 🔄 📖⚙ ⚙ ✍ ✍ ⚙ 📖⚙ 📖 ✍ ✍ ⚙ ⚙ ✍ 📖 📖🔄 🔄 🔄 🔄
© 2017 Pivotal Software, Inc. All rights reserved. Non-blocking and event-loop (Netty) IO Selector Thread Worker Threads 🔄 📖⚙ ⚙ ✍ ✍ ⚙ 📖⚙ 📖 ✍ ✍ ⚙ ⚙ ✍ 📖 📖🔄 🔄 🔄 🔄 https://github.com/backpaper0/httpserver
© 2017 Pivotal Software, Inc. All rights reserved. Use Case: Remote call with latency ☁💻 https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
© 2017 Pivotal Software, Inc. All rights reserved. Use Case: Remote call with latency ☁💻 https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8 🐌
© 2017 Pivotal Software, Inc. All rights reserved. Use Case: Remote call with latency ☁💻 https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8 🐌
© 2017 Pivotal Software, Inc. All rights reserved. Use Case: Serve a lot of slow clients https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8 📱📱 📱📱 📱📱 📱📱 📱📱 📱📱
© 2017 Pivotal Software, Inc. All rights reserved. Use Case: Push message to client https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8 💻 💬💬💬 Server-Sent Events WebSocket RabbitMQ Apache Kafka ∞
© 2017 Pivotal Software, Inc. All rights reserved. Other Use Cases •Live (continuous) database queries •UI event handling (Android) •Big Data •Real Time Analytics •HTTP/2
© 2017 Pivotal Software, Inc. All rights reserved. Going Reactive More for scalability and stability than for speed
© 2017 Pivotal Software, Inc. All rights reserved. blocking ====> event-based public class IAmBlocking { public void blockingCode() { String a = callRemoteA(); String b = callRemoteB(); String c = callRemoteC(); String d = callRemoteD(); System.out.println(a+" "+b+" "+c+" "+d); } } 😅
© 2017 Pivotal Software, Inc. All rights reserved. blocking ====> event-based public class AmIReactive { public void amIReallyReactive() { callRemoteA(a -> { callRemoteB(b -> { callRemoteC(c -> { callRemoteD(d -> println(a+" "+b+" "+c+" "+d), exd -> exd.printStackTrace()) }, exc -> exc.printStackTrace()) }, exb -> exb.printStackTrace() }, exa -> exa.printStackTrace());}} 😕
© 2017 Pivotal Software, Inc. All rights reserved. public class IAmReactive { public void iAmReallyReactive() { when(callRemoteA(), callRemoteB(), callRemoteC(), callRemoteD()) .doOnError(e -> e.printStakcTrace()) .subscribe(t -> // Tuple4<A, B, C, D> println(t.t1 +" "+t.t2+" "+t.t3+" "+t.t4)); blocking ====> event-based 😀
‹#›© 2016 Pivotal Software, Inc. All rights reserved. Reactive Streams / Reactor
© 2017 Pivotal Software, Inc. All rights reserved. Reactive Streams •Standard interfaces for asynchronous stream processing with non-blocking back pressure •De-facto standard for interoperability between reactive libraries •Implemented by http://www.reactive-streams.org/
© 2017 Pivotal Software, Inc. All rights reserved. Reactive Streams •Standard interfaces for asynchronous stream processing with non-blocking back pressure •De-facto standard for interoperability between reactive libraries •Implemented by http://www.reactive-streams.org/ RxJava 2 Reactor Akka Streams
‹#›© 2016 Pivotal Software, Inc. All rights reserved. Reactive Streams has 4 interfaces public interface Publisher<T> { void subscribe(Subscriber<? super T> s); } public interface Subscription { void request(long n); void cancel(); } public interface Subscriber<T> { void onSubscribe(Subscription s); void onNext(T t); void onError(Throwable t); void onComplete(); } public interface Processor<T, R> extends Publisher<T>, Subscriber<R> {}
© 2017 Pivotal Software, Inc. All rights reserved. Publisher Subscriber Data Flow
© 2017 Pivotal Software, Inc. All rights reserved. Publisher Subscriber subscribe Data Flow
© 2017 Pivotal Software, Inc. All rights reserved. Publisher Subscriber request(n) Backpressure Data Flow
© 2017 Pivotal Software, Inc. All rights reserved. Publisher Subscriber Backpressure onNext(data) onNext(data) onNext(data) Data Flow
© 2017 Pivotal Software, Inc. All rights reserved. Publisher Subscriber Backpressure Error|Complete Data Flow
© 2017 Pivotal Software, Inc. All rights reserved. Back-pressure •Allows to control the amount of inflight data •Regulate the transfer between •Slow publisher and fast consumer •Fast publisher and slow consumer https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
© 2017 Pivotal Software, Inc. All rights reserved. Reactive Streams based libraries
© 2017 Pivotal Software, Inc. All rights reserved. Reactive Streams based libraries RxJava Reactor Akka Streams
© 2017 Pivotal Software, Inc. All rights reserved. Reactive Streams based libraries RxJava Reactor Akka Streams
© 2017 Pivotal Software, Inc. All rights reserved. Reactor •Natively built on top of Reactive Streams with Rx API •Developed by Pivotal •Focus on Java 8 •java.util.function.* •Duration / CompletableFuture / Stream • Lightweight Rx API with 2 types: •Flux / Mono https://projectreactor.io/
© 2017 Pivotal Software, Inc. All rights reserved. Flux<T> Mono<T>
© 2017 Pivotal Software, Inc. All rights reserved. Flux<T> is a Publisher<T> for 0..n elements
© 2017 Pivotal Software, Inc. All rights reserved. Flux<T> Mono<T>
© 2017 Pivotal Software, Inc. All rights reserved. Mono<T> is a Publisher<T> for 0..1 element
© 2017 Pivotal Software, Inc. All rights reserved. Flux Flux<Integer> stream1 = Flux.just(1, 2, 3) .map(x -> x * 2) .filter(x -> x > 2); // 4, 6 Flux<String> stream2 = Flux.just("a", "b", "c"); Flux.zip(stream1, stream2)
 .doOneNext(t -> println(t.t1 + ":" + t.t2)) .subscribe(); Flux.merge(stream1, stream2)
 .doOneNext(x -> println(x)).subscribe();
© 2017 Pivotal Software, Inc. All rights reserved. Flux Flux<Integer> stream1 = Flux.just(1, 2, 3) .map(x -> x * 2) .filter(x -> x > 2); // 4, 6 Flux<String> stream2 = Flux.just("a", "b", "c"); Flux.zip(stream1, stream2)
 .doOneNext(t -> println(t.t1 + ":" + t.t2)) .subscribe(); Flux.merge(stream1, stream2)
 .doOneNext(x -> println(x)).subscribe(); 4:a 6:b
© 2017 Pivotal Software, Inc. All rights reserved. Flux Flux<Integer> stream1 = Flux.just(1, 2, 3) .map(x -> x * 2) .filter(x -> x > 2); // 4, 6 Flux<String> stream2 = Flux.just("a", "b", "c"); Flux.zip(stream1, stream2)
 .doOneNext(t -> println(t.t1 + ":" + t.t2)) .subscribe(); Flux.merge(stream1, stream2)
 .doOneNext(x -> println(x)).subscribe(); 4:a 6:b 4 6 a b c
© 2017 Pivotal Software, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message));
© 2017 Pivotal Software, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); Mono<Weather> fetchWeather(String city);
© 2017 Pivotal Software, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); times out and emits an error after 2 sec
© 2017 Pivotal Software, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); logs a message in case of errors
© 2017 Pivotal Software, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); switches to a different service in case of error
© 2017 Pivotal Software, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); transforms a weather instance into a String message
© 2017 Pivotal Software, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); triggers the processing of the chain
© 2017 Pivotal Software, Inc. All rights reserved. Type comparison No value Single value Multiple values JDK CompletableFuture<Void> CompletableFuture<T> CompletableFuture<List<T>> Reactive Streams Publisher<Void> Publisher<T> Publisher<T> RxJava1 Completable Single<T> Observable<T> RxJava2 Completable
 Maybe<T> Single<T> Maybe<T> Flowable<T> (*) Observable<T> Reactor Mono<Void> (*) Mono<T> (*) Flux<T> (*) (*) ... implements Publisher
© 2017 Pivotal Software, Inc. All rights reserved. java.util.concurrent.Flow in JDK 9 Reactive Streams JDK 9 org.reactivestreams java.util.concurrent Publisher Flow.Publisher Subscriber Flow.Subscriber Subscription Flow.Subscription Processor Flow.Processor
© 2017 Pivotal Software, Inc. All rights reserved. Reactive Streams ↔ j.u.c.Flow // Reactive Streams (Reactor) Publisher<String> pub = Flux.just("hello"); // java.util.concurrent.Flow Flow.Publisher<String> flow = JdkFlowAdapter.publisherToFlowPublisher(pub); // java.util.concurrent.Flow Flow.Publisher<String> flow = /* ... */; // Reactive Streams (Reactor) Flux<String> pub = JdkFlowAdapter.flowPublisherToFlux(flow);
‹#›© 2016 Pivotal Software, Inc. All rights reserved. Spring Framework 5.0
© 2017 Pivotal Software, Inc. All rights reserved. Spring Framework 5.0 •Performance improvements •JDK 9 - HTTP/2 •Reactive Spring •Functional APIs •Kotlin Support https://speakerdeck.com/snicoll/spring-framework-5-dot-0-themes-and-trends
© 2017 Pivotal Software, Inc. All rights reserved. Spring Framework 5.0 •Performance improvements •JDK 9 - HTTP/2 •Reactive Spring •Functional APIs •Kotlin Support https://speakerdeck.com/snicoll/spring-framework-5-dot-0-themes-and-trends
© 2017 Pivotal Software, Inc. All rights reserved.
© 2017 Pivotal Software, Inc. All rights reserved. @Controller, @RequestMapping Spring MVC Servlet API Servlet Container
© 2017 Pivotal Software, Inc. All rights reserved. @Controller, @RequestMapping Spring MVC Servlet API Servlet Container Servlet 3.1, Netty, Undertow Spring WebFlux HTTP / Reactive Streams
© 2017 Pivotal Software, Inc. All rights reserved. @Controller, @RequestMapping Spring MVC Servlet API Servlet Container Router functions Servlet 3.1, Netty, Undertow Spring WebFlux HTTP / Reactive Streams
© 2017 Pivotal Software, Inc. All rights reserved. Spring WebFlux
© 2017 Pivotal Software, Inc. All rights reserved. Spring WebFlux @RestController
 public class HelloController { @GetMapping Flux<String> hello() {
 return Flux.just("Hello", "World");
 }
 }
© 2017 Pivotal Software, Inc. All rights reserved. Spring WebFlux @RestController
 public class EchoController { @PostMapping("/echo") Flux<String> upperCase (@RequestBody Flux<String> body) {
 return body.map(String::toUpperCase);
 }
 }
© 2017 Pivotal Software, Inc. All rights reserved. Returns Infinite-Stream @RestController
 public class HelloController { @GetMapping Flux<Integer> infinite() { Stream<Integer> s = Stream.iterate(0, i -> i + 1);
 return Flux.fromStream(s);
 }}

© 2017 Pivotal Software, Inc. All rights reserved. Returns Infinite-Stream @RestController
 public class TweetController { @GetMapping Flux<Tweet> infiniteTweet() { Stream<Tweet> s = Stream.iterate(0, i -> i + 1) .map(i -> new Tweet("hello" + i));
 return Flux.fromStream(s);}}

© 2017 Pivotal Software, Inc. All rights reserved. Flux<Tweet> as a Server-Sent Events curl ... -H "Accept: text/event-stream" < HTTP/1.1 200 OK < Content-Type: text/event-stream < data: {"text":"hello0"} data: {"text":"hello1"} data: {"text":"hello2"} data: {"text":"hello3"} ...
© 2017 Pivotal Software, Inc. All rights reserved. Flux<Tweet> as a JSON Stream curl ... -H "Accept: application/stream+json" < HTTP/1.1 200 OK < Content-Type: application/stream+json < {"text":"hello0"} {"text":"hello1"} {"text":"hello2"} {"text":"hello3"} ...
© 2017 Pivotal Software, Inc. All rights reserved. WebClient •Reactive HTTP Client
© 2017 Pivotal Software, Inc. All rights reserved. WebClient •Reactive HTTP Client a nice RestTemplate alternative
© 2017 Pivotal Software, Inc. All rights reserved. WebClient •Reactive HTTP Client WebClient webClient = WebClient.create(); Mono<String> s = webClient.get() .uri("http://api.example.com") .exchange() .flatMap(res -> res.bodyToMono(String.class)); a nice RestTemplate alternative
© 2017 Pivotal Software, Inc. All rights reserved. WebClient •Reactive HTTP Client WebClient webClient = WebClient.create(); Mono<String> s = webClient.get() .uri("http://api.example.com") .retrieve() .bodyToMono(String.class);
© 2017 Pivotal Software, Inc. All rights reserved. WebClient •Reactive HTTP Client WebClient webClient = WebClient.create(); Flux<Tweet> tweets = webClient.get() .uri("http://api.example.com") .retrieve() .bodyToFlux(Tweet.class);
© 2017 Pivotal Software, Inc. All rights reserved. Flux<Tweet> WebClient Streaming API
© 2017 Pivotal Software, Inc. All rights reserved. Flux<Tweet> ✔ Reactive API ✔ Can consume (infinite) streams WebClient Streaming API
© 2017 Pivotal Software, Inc. All rights reserved. Flux.zip(tweets,	issues) WebClient Streaming API REST API WebClient
© 2017 Pivotal Software, Inc. All rights reserved. Flux.zip(tweets,	issues) ✔ Chain and compose WebClient Streaming API REST API WebClient
© 2017 Pivotal Software, Inc. All rights reserved. WebClient Web handler WebFlux
© 2017 Pivotal Software, Inc. All rights reserved. WebClient Web handler WebFlux
© 2017 Pivotal Software, Inc. All rights reserved. WebClient Web handler WebFlux ✔ Shared resources (event loop, buffers) ✔ Built-in mocking capabilities
© 2017 Pivotal Software, Inc. All rights reserved. Router Functions
© 2017 Pivotal Software, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return RouterFunctions.route( RequestPredicates.GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
© 2017 Pivotal Software, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return RouterFunctions.route( RequestPredicates.GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
© 2017 Pivotal Software, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route( RequestPredicates.GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
© 2017 Pivotal Software, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route( RequestPredicates.GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
© 2017 Pivotal Software, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route(GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
© 2017 Pivotal Software, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route(GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
© 2017 Pivotal Software, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route(GET("/"), req -> ok() .body(Mono.just("Hello","World"), String.class));
 }
© 2017 Pivotal Software, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() { return route(POST("/echo"), req -> { Mono<String> body = req .bodyToMono(String.class) .map(String::toUpperCase); return ok().body(body, String.class)); });}
© 2017 Pivotal Software, Inc. All rights reserved. Spring Boot 2.0 Spring Boot 2.0 supports Spring 5 and WebFlux ✨
© 2017 Pivotal Software, Inc. All rights reserved. start.spring.io
‹#›© 2016 Pivotal Software, Inc. All rights reserved. DEMO
© 2017 Pivotal Software, Inc. All rights reserved. Spring MVC VS Spring WebFlux @GetMapping Flux<String> hello() {
 return Flux.just("Hello") .delayElements( ofSeconds(1));
 } @GetMapping String hello() { Thread.sleep(1000);
 return"Hello";
 } server.tomcat.max-threads=200 (default) https://gist.github.com/making/f32e81c5684a5fd810039854091dd793 Tomcat Netty
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 100
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 100 Transaction rate: 94.79 trans/sec Response time: 1.05 sec Live peek threads: 129
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 100 Transaction rate: 94.79 trans/sec Response time: 1.05 sec Live peek threads: 129 Transaction rate: 94.88 trans/sec Response time: 1.05 sec Live peek threads: 30
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 200
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 200 Transaction rate: 182.65 trans/sec Response time: 1.07 sec Live peek threads: 218
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 200 Transaction rate: 182.65 trans/sec Response time: 1.07 sec Live peek threads: 218 Transaction rate: 184.50 trans/sec Response time: 1.06 sec Live peek threads: 30
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 300
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 300 Transaction rate: 192.31 trans/sec Response time: 1.51 sec Live peek threads: 218
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 300 Transaction rate: 192.31 trans/sec Response time: 1.51 sec Live peek threads: 218 Transaction rate: 278.55 trans/sec Response time: 1.04 sec Live peek threads: 30
© 2017 Pivotal Software, Inc. All rights reserved. Blocking in WebFlux?? @GetMapping Flux<String> hello() { Thread.sleep(1000); // blocking!
 return Flux.just("Hello");
 }
© 2017 Pivotal Software, Inc. All rights reserved. Concurrent users = 100 Transaction rate: 7.94 trans/sec Response time: 12 sec Live peek threads: 22 😱
‹#›© 2016 Pivotal Software, Inc. All rights reserved. End-to-End Reactive
© 2017 Pivotal Software, Inc. All rights reserved. End-to-End Reactive Controller Repository Service Filter Publisher Publisher Publisher Publisher Publisher Publisher Publisher Publisher
© 2017 Pivotal Software, Inc. All rights reserved. End-to-End Reactive Controller Repository Service Filter Publisher Publisher Publisher Publisher Publisher Publisher Publisher Publisher
© 2017 Pivotal Software, Inc. All rights reserved. Spring Projects Reactor Ecosystem Spring Security Spring Data Spring Cloud Spring Integration Reactor Projects Reactor Netty Reactor Kafka Lettuce Thymeleaf
© 2017 Pivotal Software, Inc. All rights reserved. Spring Projects Reactor Ecosystem Spring Security Spring Data Spring Cloud Spring Integration Reactor Projects Reactor Netty Reactor Kafka Lettuce MongoDB Redis Cassandra Couchbase Thymeleaf
© 2017 Pivotal Software, Inc. All rights reserved. Spring Data Release Train Kay •Supports •Reactive Template •Reactive Repository
© 2017 Pivotal Software, Inc. All rights reserved. Reactive Repository public interface ReactiveCrudRepository<ID,T> { Mono<T> findById(ID id); Mono<T> findById(Mono<ID> id); Flux<T> findAll(); Mono<Long> count(); Mono<T> save(T entity); Mono<T> saveAll(Publisher<T> entityStream); Mono<Void> delete(T entity) // ... }
© 2017 Pivotal Software, Inc. All rights reserved. @Tailable for Infinite streams public interface PersonRepository extends ReactiveMongoRepository<Person,String> { @Tailable Flux<Person> findByFirstname(String firstname); }
© 2017 Pivotal Software, Inc. All rights reserved. What about JPA/JDBC? 🤔
© 2017 Pivotal Software, Inc. All rights reserved. What about JPA/JDBC? •JDBC is blocking ⌛ •JPA is blocking ⌛ 🤔
© 2017 Pivotal Software, Inc. All rights reserved. What about JPA/JDBC? •JDBC is blocking ⌛ •JPA is blocking ⌛ 🤔 https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/ CONF1578%2020160916.pdf https://www.voxxed.com/blog/2016/09/non-blocking-database-access/ •Non-Blocking JDBC in JDK 10?
© 2017 Pivotal Software, Inc. All rights reserved. Switching execution context BlockingRepository<User> repo = ...; Flux<User> users = Flux.defer(() -> Flux.fromIterable(repo.findAll())) .subscribeOn(Schedulers.elastic()); Make the subscription and request happen on a particular thread
© 2017 Pivotal Software, Inc. All rights reserved. Switching execution context Flux<User> users = ...; BlockingRepository<User> repo = ...; users.publishOn(Schedulers.elastic()) .doOneNext(u -> repo.save(u)) .then() ; Switch rest of the flux on a particular thread
‹#›© 2016 Pivotal Software, Inc. All rights reserved. Reactive Web Applications Example
© 2017 Pivotal Software, Inc. All rights reserved. 💻 💻 💻 Server-Sent Events POST PUBLISH SUBSCRIBE INCR Pub/Sub Application bit.ly/jdtd1d5
© 2017 Pivotal Software, Inc. All rights reserved. API Gateway • Rate Limiter • Web Application Firewall
© 2017 Pivotal Software, Inc. All rights reserved. API Gateway • Rate Limiter • Web Application Firewall ✅ Spring Cloud Gateway
© 2017 Pivotal Software, Inc. All rights reserved. Route Services in Cloud Foundry
© 2017 Pivotal Software, Inc. All rights reserved. FFB (Frontend for Backend) 💻 📱 Frontend Backend
© 2017 Pivotal Software, Inc. All rights reserved. Reactive Everywhere CF Java Client Firehose Nozzle Firehose Nozzle Cloud Foundry 💻 Firehose Doppler Endpoint WebSocket Rector Kafka (Publisher) Rector Kafka (Consumer) Reactor Netty Sever-Sent Event Spring WebFluxLog, Metrics
© 2017 Pivotal Software, Inc. All rights reserved. Spring WebFlux • https://blog.ik.am/entries/417 • https://blog.ik.am/entries/418 • ...
© 2017 Pivotal Software, Inc. All rights reserved. Thank you!! • Handson • https://github.com/reactor/lite-rx-api-hands-on • Slides • https://speakerdeck.com/simonbasle/reactor-3 • https://speakerdeck.com/sdeleuze/developing-reactive-applications-with- reactive-streams-and-java-8 • https://speakerdeck.com/snicoll/spring-framework-5-dot-0-themes-and- trends • https://speakerdeck.com/mp911de/reactive-spring • https://speakerdeck.com/christophstrobl/sneak-peek-on-spring-data-kay • https://speakerdeck.com/normanmaurer/netty-meetup-2017-san-francisco

Spring Framework 5.0による Reactive Web Application #JavaDayTokyo

  • 1.
    ‹#›© 2016 PivotalSoftware, Inc. All rights reserved. ‹#›© 2017 Pivotal Software, Inc. All rights reserved. Spring Framework 5.0 Reactive Web Application Toshiaki Maki (@making) 2016-05-17 Java Day Tokyo 2017
  • 2.
    © 2017 PivotalSoftware, Inc. All rights reserved. Who am I ? • Toshiaki Maki (@making) https://blog.ik.am • Sr. Solutions Architect @Pivotal • Spring Framework 💖 • Cloud Foundry 💖 bit.ly/hajiboot2
  • 3.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive???
  • 4.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive??? "In a nutshell reactive programming is about non-blocking, event-driven applications that scale with a small number of threads with backpressure as a key ingredient that remains to ensure producers do not overwhelm consumers" - Rossen Stoyanchev
  • 5.
    © 2017 PivotalSoftware, Inc. All rights reserved. Sync / Blocking https://speakerdeck.com/simonbasle/reactor-3
  • 6.
    © 2017 PivotalSoftware, Inc. All rights reserved. Sync / Blocking https://speakerdeck.com/simonbasle/reactor-3 I/O main thread processing resumes
  • 7.
    © 2017 PivotalSoftware, Inc. All rights reserved. Sync / Blocking https://speakerdeck.com/simonbasle/reactor-3 I/O main thread processing resumes 😴 app does nothing
  • 8.
    © 2017 PivotalSoftware, Inc. All rights reserved. Async & Blocking https://speakerdeck.com/simonbasle/reactor-3
  • 9.
    © 2017 PivotalSoftware, Inc. All rights reserved. Async & Blocking https://speakerdeck.com/simonbasle/reactor-3 main thread wait & join
  • 10.
    © 2017 PivotalSoftware, Inc. All rights reserved. Async & Blocking https://speakerdeck.com/simonbasle/reactor-3 main thread wait & join complex new threads, costly
  • 11.
    © 2017 PivotalSoftware, Inc. All rights reserved. Async & Non-Blocking
  • 12.
    © 2017 PivotalSoftware, Inc. All rights reserved. Async & Non-Blocking https://speakerdeck.com/simonbasle/reactor-3 Event Loop chunks processing in non-blocking
  • 13.
    © 2017 PivotalSoftware, Inc. All rights reserved. Blocking + Thread pools (Servlet) HTTP request HTTP response 📖⏳ ⚙⏳ ✍⏳ Thread
  • 14.
    © 2017 PivotalSoftware, Inc. All rights reserved. Non-blocking and event-loop (Netty) IO Selector Thread Worker Threads 🔄 📖⚙ ⚙ ✍ ✍ ⚙ 📖⚙ 📖 ✍ ✍ ⚙ ⚙ ✍ 📖 📖🔄 🔄 🔄 🔄
  • 15.
    © 2017 PivotalSoftware, Inc. All rights reserved. Non-blocking and event-loop (Netty) IO Selector Thread Worker Threads 🔄 📖⚙ ⚙ ✍ ✍ ⚙ 📖⚙ 📖 ✍ ✍ ⚙ ⚙ ✍ 📖 📖🔄 🔄 🔄 🔄 https://github.com/backpaper0/httpserver
  • 16.
    © 2017 PivotalSoftware, Inc. All rights reserved. Use Case: Remote call with latency ☁💻 https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
  • 17.
    © 2017 PivotalSoftware, Inc. All rights reserved. Use Case: Remote call with latency ☁💻 https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8 🐌
  • 18.
    © 2017 PivotalSoftware, Inc. All rights reserved. Use Case: Remote call with latency ☁💻 https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8 🐌
  • 19.
    © 2017 PivotalSoftware, Inc. All rights reserved. Use Case: Serve a lot of slow clients https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8 📱📱 📱📱 📱📱 📱📱 📱📱 📱📱
  • 20.
    © 2017 PivotalSoftware, Inc. All rights reserved. Use Case: Push message to client https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8 💻 💬💬💬 Server-Sent Events WebSocket RabbitMQ Apache Kafka ∞
  • 21.
    © 2017 PivotalSoftware, Inc. All rights reserved. Other Use Cases •Live (continuous) database queries •UI event handling (Android) •Big Data •Real Time Analytics •HTTP/2
  • 22.
    © 2017 PivotalSoftware, Inc. All rights reserved. Going Reactive More for scalability and stability than for speed
  • 23.
    © 2017 PivotalSoftware, Inc. All rights reserved. blocking ====> event-based public class IAmBlocking { public void blockingCode() { String a = callRemoteA(); String b = callRemoteB(); String c = callRemoteC(); String d = callRemoteD(); System.out.println(a+" "+b+" "+c+" "+d); } } 😅
  • 24.
    © 2017 PivotalSoftware, Inc. All rights reserved. blocking ====> event-based public class AmIReactive { public void amIReallyReactive() { callRemoteA(a -> { callRemoteB(b -> { callRemoteC(c -> { callRemoteD(d -> println(a+" "+b+" "+c+" "+d), exd -> exd.printStackTrace()) }, exc -> exc.printStackTrace()) }, exb -> exb.printStackTrace() }, exa -> exa.printStackTrace());}} 😕
  • 25.
    © 2017 PivotalSoftware, Inc. All rights reserved. public class IAmReactive { public void iAmReallyReactive() { when(callRemoteA(), callRemoteB(), callRemoteC(), callRemoteD()) .doOnError(e -> e.printStakcTrace()) .subscribe(t -> // Tuple4<A, B, C, D> println(t.t1 +" "+t.t2+" "+t.t3+" "+t.t4)); blocking ====> event-based 😀
  • 26.
    ‹#›© 2016 PivotalSoftware, Inc. All rights reserved. Reactive Streams / Reactor
  • 27.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive Streams •Standard interfaces for asynchronous stream processing with non-blocking back pressure •De-facto standard for interoperability between reactive libraries •Implemented by http://www.reactive-streams.org/
  • 28.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive Streams •Standard interfaces for asynchronous stream processing with non-blocking back pressure •De-facto standard for interoperability between reactive libraries •Implemented by http://www.reactive-streams.org/ RxJava 2 Reactor Akka Streams
  • 29.
    ‹#›© 2016 PivotalSoftware, Inc. All rights reserved. Reactive Streams has 4 interfaces public interface Publisher<T> { void subscribe(Subscriber<? super T> s); } public interface Subscription { void request(long n); void cancel(); } public interface Subscriber<T> { void onSubscribe(Subscription s); void onNext(T t); void onError(Throwable t); void onComplete(); } public interface Processor<T, R> extends Publisher<T>, Subscriber<R> {}
  • 30.
    © 2017 PivotalSoftware, Inc. All rights reserved. Publisher Subscriber Data Flow
  • 31.
    © 2017 PivotalSoftware, Inc. All rights reserved. Publisher Subscriber subscribe Data Flow
  • 32.
    © 2017 PivotalSoftware, Inc. All rights reserved. Publisher Subscriber request(n) Backpressure Data Flow
  • 33.
    © 2017 PivotalSoftware, Inc. All rights reserved. Publisher Subscriber Backpressure onNext(data) onNext(data) onNext(data) Data Flow
  • 34.
    © 2017 PivotalSoftware, Inc. All rights reserved. Publisher Subscriber Backpressure Error|Complete Data Flow
  • 35.
    © 2017 PivotalSoftware, Inc. All rights reserved. Back-pressure •Allows to control the amount of inflight data •Regulate the transfer between •Slow publisher and fast consumer •Fast publisher and slow consumer https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
  • 36.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive Streams based libraries
  • 37.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive Streams based libraries RxJava Reactor Akka Streams
  • 38.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive Streams based libraries RxJava Reactor Akka Streams
  • 39.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactor •Natively built on top of Reactive Streams with Rx API •Developed by Pivotal •Focus on Java 8 •java.util.function.* •Duration / CompletableFuture / Stream • Lightweight Rx API with 2 types: •Flux / Mono https://projectreactor.io/
  • 40.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux<T> Mono<T>
  • 41.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux<T> is a Publisher<T> for 0..n elements
  • 42.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux<T> Mono<T>
  • 43.
    © 2017 PivotalSoftware, Inc. All rights reserved. Mono<T> is a Publisher<T> for 0..1 element
  • 44.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux Flux<Integer> stream1 = Flux.just(1, 2, 3) .map(x -> x * 2) .filter(x -> x > 2); // 4, 6 Flux<String> stream2 = Flux.just("a", "b", "c"); Flux.zip(stream1, stream2)
 .doOneNext(t -> println(t.t1 + ":" + t.t2)) .subscribe(); Flux.merge(stream1, stream2)
 .doOneNext(x -> println(x)).subscribe();
  • 45.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux Flux<Integer> stream1 = Flux.just(1, 2, 3) .map(x -> x * 2) .filter(x -> x > 2); // 4, 6 Flux<String> stream2 = Flux.just("a", "b", "c"); Flux.zip(stream1, stream2)
 .doOneNext(t -> println(t.t1 + ":" + t.t2)) .subscribe(); Flux.merge(stream1, stream2)
 .doOneNext(x -> println(x)).subscribe(); 4:a 6:b
  • 46.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux Flux<Integer> stream1 = Flux.just(1, 2, 3) .map(x -> x * 2) .filter(x -> x > 2); // 4, 6 Flux<String> stream2 = Flux.just("a", "b", "c"); Flux.zip(stream1, stream2)
 .doOneNext(t -> println(t.t1 + ":" + t.t2)) .subscribe(); Flux.merge(stream1, stream2)
 .doOneNext(x -> println(x)).subscribe(); 4:a 6:b 4 6 a b c
  • 47.
    © 2017 PivotalSoftware, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message));
  • 48.
    © 2017 PivotalSoftware, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); Mono<Weather> fetchWeather(String city);
  • 49.
    © 2017 PivotalSoftware, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); times out and emits an error after 2 sec
  • 50.
    © 2017 PivotalSoftware, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); logs a message in case of errors
  • 51.
    © 2017 PivotalSoftware, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); switches to a different service in case of error
  • 52.
    © 2017 PivotalSoftware, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); transforms a weather instance into a String message
  • 53.
    © 2017 PivotalSoftware, Inc. All rights reserved. String location = "Tokyo, Japan"; mainService.fetchWeather(location) .timeout(Duration.ofSeconds(2)) .doOnError(ex -> logger.error(ex.getMessage())) .onErrorResume(ex -> backupService.fetchWeather(location)) .map(w -> format("Weather in %s is %s", w.location(), w.description())) .subscribe(message -> logger.info(message)); triggers the processing of the chain
  • 54.
    © 2017 PivotalSoftware, Inc. All rights reserved. Type comparison No value Single value Multiple values JDK CompletableFuture<Void> CompletableFuture<T> CompletableFuture<List<T>> Reactive Streams Publisher<Void> Publisher<T> Publisher<T> RxJava1 Completable Single<T> Observable<T> RxJava2 Completable
 Maybe<T> Single<T> Maybe<T> Flowable<T> (*) Observable<T> Reactor Mono<Void> (*) Mono<T> (*) Flux<T> (*) (*) ... implements Publisher
  • 55.
    © 2017 PivotalSoftware, Inc. All rights reserved. java.util.concurrent.Flow in JDK 9 Reactive Streams JDK 9 org.reactivestreams java.util.concurrent Publisher Flow.Publisher Subscriber Flow.Subscriber Subscription Flow.Subscription Processor Flow.Processor
  • 56.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive Streams ↔ j.u.c.Flow // Reactive Streams (Reactor) Publisher<String> pub = Flux.just("hello"); // java.util.concurrent.Flow Flow.Publisher<String> flow = JdkFlowAdapter.publisherToFlowPublisher(pub); // java.util.concurrent.Flow Flow.Publisher<String> flow = /* ... */; // Reactive Streams (Reactor) Flux<String> pub = JdkFlowAdapter.flowPublisherToFlux(flow);
  • 57.
    ‹#›© 2016 PivotalSoftware, Inc. All rights reserved. Spring Framework 5.0
  • 58.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring Framework 5.0 •Performance improvements •JDK 9 - HTTP/2 •Reactive Spring •Functional APIs •Kotlin Support https://speakerdeck.com/snicoll/spring-framework-5-dot-0-themes-and-trends
  • 59.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring Framework 5.0 •Performance improvements •JDK 9 - HTTP/2 •Reactive Spring •Functional APIs •Kotlin Support https://speakerdeck.com/snicoll/spring-framework-5-dot-0-themes-and-trends
  • 60.
    © 2017 PivotalSoftware, Inc. All rights reserved.
  • 61.
    © 2017 PivotalSoftware, Inc. All rights reserved. @Controller, @RequestMapping Spring MVC Servlet API Servlet Container
  • 62.
    © 2017 PivotalSoftware, Inc. All rights reserved. @Controller, @RequestMapping Spring MVC Servlet API Servlet Container Servlet 3.1, Netty, Undertow Spring WebFlux HTTP / Reactive Streams
  • 63.
    © 2017 PivotalSoftware, Inc. All rights reserved. @Controller, @RequestMapping Spring MVC Servlet API Servlet Container Router functions Servlet 3.1, Netty, Undertow Spring WebFlux HTTP / Reactive Streams
  • 64.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring WebFlux
  • 65.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring WebFlux @RestController
 public class HelloController { @GetMapping Flux<String> hello() {
 return Flux.just("Hello", "World");
 }
 }
  • 66.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring WebFlux @RestController
 public class EchoController { @PostMapping("/echo") Flux<String> upperCase (@RequestBody Flux<String> body) {
 return body.map(String::toUpperCase);
 }
 }
  • 67.
    © 2017 PivotalSoftware, Inc. All rights reserved. Returns Infinite-Stream @RestController
 public class HelloController { @GetMapping Flux<Integer> infinite() { Stream<Integer> s = Stream.iterate(0, i -> i + 1);
 return Flux.fromStream(s);
 }}

  • 68.
    © 2017 PivotalSoftware, Inc. All rights reserved. Returns Infinite-Stream @RestController
 public class TweetController { @GetMapping Flux<Tweet> infiniteTweet() { Stream<Tweet> s = Stream.iterate(0, i -> i + 1) .map(i -> new Tweet("hello" + i));
 return Flux.fromStream(s);}}

  • 69.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux<Tweet> as a Server-Sent Events curl ... -H "Accept: text/event-stream" < HTTP/1.1 200 OK < Content-Type: text/event-stream < data: {"text":"hello0"} data: {"text":"hello1"} data: {"text":"hello2"} data: {"text":"hello3"} ...
  • 70.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux<Tweet> as a JSON Stream curl ... -H "Accept: application/stream+json" < HTTP/1.1 200 OK < Content-Type: application/stream+json < {"text":"hello0"} {"text":"hello1"} {"text":"hello2"} {"text":"hello3"} ...
  • 71.
    © 2017 PivotalSoftware, Inc. All rights reserved. WebClient •Reactive HTTP Client
  • 72.
    © 2017 PivotalSoftware, Inc. All rights reserved. WebClient •Reactive HTTP Client a nice RestTemplate alternative
  • 73.
    © 2017 PivotalSoftware, Inc. All rights reserved. WebClient •Reactive HTTP Client WebClient webClient = WebClient.create(); Mono<String> s = webClient.get() .uri("http://api.example.com") .exchange() .flatMap(res -> res.bodyToMono(String.class)); a nice RestTemplate alternative
  • 74.
    © 2017 PivotalSoftware, Inc. All rights reserved. WebClient •Reactive HTTP Client WebClient webClient = WebClient.create(); Mono<String> s = webClient.get() .uri("http://api.example.com") .retrieve() .bodyToMono(String.class);
  • 75.
    © 2017 PivotalSoftware, Inc. All rights reserved. WebClient •Reactive HTTP Client WebClient webClient = WebClient.create(); Flux<Tweet> tweets = webClient.get() .uri("http://api.example.com") .retrieve() .bodyToFlux(Tweet.class);
  • 76.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux<Tweet> WebClient Streaming API
  • 77.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux<Tweet> ✔ Reactive API ✔ Can consume (infinite) streams WebClient Streaming API
  • 78.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux.zip(tweets, issues) WebClient Streaming API REST API WebClient
  • 79.
    © 2017 PivotalSoftware, Inc. All rights reserved. Flux.zip(tweets, issues) ✔ Chain and compose WebClient Streaming API REST API WebClient
  • 80.
    © 2017 PivotalSoftware, Inc. All rights reserved. WebClient Web handler WebFlux
  • 81.
    © 2017 PivotalSoftware, Inc. All rights reserved. WebClient Web handler WebFlux
  • 82.
    © 2017 PivotalSoftware, Inc. All rights reserved. WebClient Web handler WebFlux ✔ Shared resources (event loop, buffers) ✔ Built-in mocking capabilities
  • 83.
    © 2017 PivotalSoftware, Inc. All rights reserved. Router Functions
  • 84.
    © 2017 PivotalSoftware, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return RouterFunctions.route( RequestPredicates.GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
  • 85.
    © 2017 PivotalSoftware, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return RouterFunctions.route( RequestPredicates.GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
  • 86.
    © 2017 PivotalSoftware, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route( RequestPredicates.GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
  • 87.
    © 2017 PivotalSoftware, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route( RequestPredicates.GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
  • 88.
    © 2017 PivotalSoftware, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route(GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
  • 89.
    © 2017 PivotalSoftware, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route(GET("/"), req -> ServerResponse.ok() .body(Mono.just("Hello","World"), String.class));
 }
  • 90.
    © 2017 PivotalSoftware, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() {
 return route(GET("/"), req -> ok() .body(Mono.just("Hello","World"), String.class));
 }
  • 91.
    © 2017 PivotalSoftware, Inc. All rights reserved. Router Functions RouterFunctions<ServerResponse> routes() { return route(POST("/echo"), req -> { Mono<String> body = req .bodyToMono(String.class) .map(String::toUpperCase); return ok().body(body, String.class)); });}
  • 92.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring Boot 2.0 Spring Boot 2.0 supports Spring 5 and WebFlux ✨
  • 93.
    © 2017 PivotalSoftware, Inc. All rights reserved. start.spring.io
  • 94.
    ‹#›© 2016 PivotalSoftware, Inc. All rights reserved. DEMO
  • 95.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring MVC VS Spring WebFlux @GetMapping Flux<String> hello() {
 return Flux.just("Hello") .delayElements( ofSeconds(1));
 } @GetMapping String hello() { Thread.sleep(1000);
 return"Hello";
 } server.tomcat.max-threads=200 (default) https://gist.github.com/making/f32e81c5684a5fd810039854091dd793 Tomcat Netty
  • 96.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 100
  • 97.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 100 Transaction rate: 94.79 trans/sec Response time: 1.05 sec Live peek threads: 129
  • 98.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 100 Transaction rate: 94.79 trans/sec Response time: 1.05 sec Live peek threads: 129 Transaction rate: 94.88 trans/sec Response time: 1.05 sec Live peek threads: 30
  • 99.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 200
  • 100.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 200 Transaction rate: 182.65 trans/sec Response time: 1.07 sec Live peek threads: 218
  • 101.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 200 Transaction rate: 182.65 trans/sec Response time: 1.07 sec Live peek threads: 218 Transaction rate: 184.50 trans/sec Response time: 1.06 sec Live peek threads: 30
  • 102.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 300
  • 103.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 300 Transaction rate: 192.31 trans/sec Response time: 1.51 sec Live peek threads: 218
  • 104.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 300 Transaction rate: 192.31 trans/sec Response time: 1.51 sec Live peek threads: 218 Transaction rate: 278.55 trans/sec Response time: 1.04 sec Live peek threads: 30
  • 105.
    © 2017 PivotalSoftware, Inc. All rights reserved. Blocking in WebFlux?? @GetMapping Flux<String> hello() { Thread.sleep(1000); // blocking!
 return Flux.just("Hello");
 }
  • 106.
    © 2017 PivotalSoftware, Inc. All rights reserved. Concurrent users = 100 Transaction rate: 7.94 trans/sec Response time: 12 sec Live peek threads: 22 😱
  • 107.
    ‹#›© 2016 PivotalSoftware, Inc. All rights reserved. End-to-End Reactive
  • 108.
    © 2017 PivotalSoftware, Inc. All rights reserved. End-to-End Reactive Controller Repository Service Filter Publisher Publisher Publisher Publisher Publisher Publisher Publisher Publisher
  • 109.
    © 2017 PivotalSoftware, Inc. All rights reserved. End-to-End Reactive Controller Repository Service Filter Publisher Publisher Publisher Publisher Publisher Publisher Publisher Publisher
  • 110.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring Projects Reactor Ecosystem Spring Security Spring Data Spring Cloud Spring Integration Reactor Projects Reactor Netty Reactor Kafka Lettuce Thymeleaf
  • 111.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring Projects Reactor Ecosystem Spring Security Spring Data Spring Cloud Spring Integration Reactor Projects Reactor Netty Reactor Kafka Lettuce MongoDB Redis Cassandra Couchbase Thymeleaf
  • 112.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring Data Release Train Kay •Supports •Reactive Template •Reactive Repository
  • 113.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive Repository public interface ReactiveCrudRepository<ID,T> { Mono<T> findById(ID id); Mono<T> findById(Mono<ID> id); Flux<T> findAll(); Mono<Long> count(); Mono<T> save(T entity); Mono<T> saveAll(Publisher<T> entityStream); Mono<Void> delete(T entity) // ... }
  • 114.
    © 2017 PivotalSoftware, Inc. All rights reserved. @Tailable for Infinite streams public interface PersonRepository extends ReactiveMongoRepository<Person,String> { @Tailable Flux<Person> findByFirstname(String firstname); }
  • 115.
    © 2017 PivotalSoftware, Inc. All rights reserved. What about JPA/JDBC? 🤔
  • 116.
    © 2017 PivotalSoftware, Inc. All rights reserved. What about JPA/JDBC? •JDBC is blocking ⌛ •JPA is blocking ⌛ 🤔
  • 117.
    © 2017 PivotalSoftware, Inc. All rights reserved. What about JPA/JDBC? •JDBC is blocking ⌛ •JPA is blocking ⌛ 🤔 https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/ CONF1578%2020160916.pdf https://www.voxxed.com/blog/2016/09/non-blocking-database-access/ •Non-Blocking JDBC in JDK 10?
  • 118.
    © 2017 PivotalSoftware, Inc. All rights reserved. Switching execution context BlockingRepository<User> repo = ...; Flux<User> users = Flux.defer(() -> Flux.fromIterable(repo.findAll())) .subscribeOn(Schedulers.elastic()); Make the subscription and request happen on a particular thread
  • 119.
    © 2017 PivotalSoftware, Inc. All rights reserved. Switching execution context Flux<User> users = ...; BlockingRepository<User> repo = ...; users.publishOn(Schedulers.elastic()) .doOneNext(u -> repo.save(u)) .then() ; Switch rest of the flux on a particular thread
  • 120.
    ‹#›© 2016 PivotalSoftware, Inc. All rights reserved. Reactive Web Applications Example
  • 121.
    © 2017 PivotalSoftware, Inc. All rights reserved. 💻 💻 💻 Server-Sent Events POST PUBLISH SUBSCRIBE INCR Pub/Sub Application bit.ly/jdtd1d5
  • 122.
    © 2017 PivotalSoftware, Inc. All rights reserved. API Gateway • Rate Limiter • Web Application Firewall
  • 123.
    © 2017 PivotalSoftware, Inc. All rights reserved. API Gateway • Rate Limiter • Web Application Firewall ✅ Spring Cloud Gateway
  • 124.
    © 2017 PivotalSoftware, Inc. All rights reserved. Route Services in Cloud Foundry
  • 125.
    © 2017 PivotalSoftware, Inc. All rights reserved. FFB (Frontend for Backend) 💻 📱 Frontend Backend
  • 126.
    © 2017 PivotalSoftware, Inc. All rights reserved. Reactive Everywhere CF Java Client Firehose Nozzle Firehose Nozzle Cloud Foundry 💻 Firehose Doppler Endpoint WebSocket Rector Kafka (Publisher) Rector Kafka (Consumer) Reactor Netty Sever-Sent Event Spring WebFluxLog, Metrics
  • 127.
    © 2017 PivotalSoftware, Inc. All rights reserved. Spring WebFlux • https://blog.ik.am/entries/417 • https://blog.ik.am/entries/418 • ...
  • 128.
    © 2017 PivotalSoftware, Inc. All rights reserved. Thank you!! • Handson • https://github.com/reactor/lite-rx-api-hands-on • Slides • https://speakerdeck.com/simonbasle/reactor-3 • https://speakerdeck.com/sdeleuze/developing-reactive-applications-with- reactive-streams-and-java-8 • https://speakerdeck.com/snicoll/spring-framework-5-dot-0-themes-and- trends • https://speakerdeck.com/mp911de/reactive-spring • https://speakerdeck.com/christophstrobl/sneak-peek-on-spring-data-kay • https://speakerdeck.com/normanmaurer/netty-meetup-2017-san-francisco