SlideShare une entreprise Scribd logo
1  sur  144
1
Introduction to Spring WebFlux
2017-11-24
Toshiaki Maki (@making) #jsug #sf_a1
Who am I ?
2
Toshiaki Maki (@making) https://blog.ik.am
Sr. Solutions Architect @Pivotal Japan
Spring Framework 💖
Cloud Foundry 💖
DEMO
4
📱📱📱📱📱📱📱📱📱
📱📱📱📱📱📱📱📱📱4
📱📱📱📱📱📱📱📱📱4
🗄
📈
Devices Dashboard
HTTP POST
Server-Sent Events
∞🔄
http://bit.ly/demoiot
❓How many threads are this app using?
5
❓How many threads are this app using?
5
1. 200 -
2. 100 - 200
3. 50 - 100
4. 10 - 50
5. 1 - 10
6
Web Stacks in Spring 5
7
Servlet Container
Servlet API
Spring MVC
Servlet Stack
Web Stacks in Spring 5
7
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet Stack
Web Stacks in Spring 5
7
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet StackBlocking
Web Stacks in Spring 5
7
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet StackBlocking
Web Stacks in Spring 5
7
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet StackBlocking
Non-Blocking
Web Stacks in Spring 5
7
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet StackBlocking
Non-Blocking
8
Servlet StackThread
Thread
Thread
Thread
Thread
…⏳
9
Reactive Stack
🔄 Thread
🔄 Thread
🔄 Thread
🔄 Thread
❓Why are we introducing Spring WebFlux?
10
❓Why are we introducing Spring WebFlux?
10
The goal of Spring WebFlux is to offer Spring
developers a non-blocking event-loop style
programming model similar to node.js.
the non-blocking async programming model is more
efficient for latency-sensitive workloads.
– Blocking threads consume resources
– mobile applications and interconnected
microservices
❓Why are we introducing Spring WebFlux?
10
The goal of Spring WebFlux is to offer Spring
developers a non-blocking event-loop style
programming model similar to node.js.
Web Stacks in Spring 5
11
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet Stack
Publisher Subscriber
Reactive Streams
2
Publisher Subscriber
subscribe
Reactive Streams
2
Publisher Subscriber
request(n)
Backpressure
Reactive Streams
2
Publisher Subscriber
Backpressure
onNext(data)
onNext(data)
onNext(data)
Reactive Streams
2
Publisher Subscriber
Backpressure
Error|Complete
Reactive Streams
2
13
13
4
Flux<T>
Mono<T>
5
Flux<T> is a Publisher<T> for 0..n elements
6
Flux<T>
Mono<T>
7
Mono<T> is a Publisher<T> for 0..1 element
Reactor
18
Flux<String> s = Flux
.just("a", "b", "c", "d")
.map(String::toUpperCase);
s.log("demo").subscribe();
Reactor
18
Flux<String> s = Flux
.just("a", "b", "c", "d")
.map(String::toUpperCase);
s.log("demo").subscribe();
Need to be subscribed!
Reactor
18
Flux<String> s = Flux
.just("a", "b", "c", "d")
.map(String::toUpperCase);
s.log("demo").subscribe();
Need to be subscribed!
00:58:33.902 [main] INFO demo - | request(unbounded)
00:58:33.903 [main] INFO demo - | onNext(A)
00:58:33.903 [main] INFO demo - | onNext(B)
00:58:33.903 [main] INFO demo - | onNext(C)
00:58:33.903 [main] INFO demo - | onNext(D)
00:58:33.903 [main] INFO demo - | onComplete()
Reactor
19
Flux<String> s = Flux
.just("a", "b", "c", "d")
.map(String::toUpperCase)
.delayElements(Duration.ofSeconds(1));
s.log("demo").subscribe();
Reactor
19
Flux<String> s = Flux
.just("a", "b", "c", "d")
.map(String::toUpperCase)
.delayElements(Duration.ofSeconds(1));
s.log("demo").subscribe();
00:59:42.949 [main] INFO demo - request(unbounded)
00:59:43.992 [parallel-1] INFO demo - onNext(A)
00:59:44.994 [parallel-2] INFO demo - onNext(B)
00:59:45.997 [parallel-3] INFO demo - onNext(C)
00:59:46.999 [parallel-4] INFO demo - onNext(D)
00:59:47.001 [parallel-4] INFO demo - onComplete()
Reactor (Hot Stream♨)
20
Flux<String> s = Flux.<String>create(sink ->
sink.next(...);
});
s.log("demo").subscribe();
Reactor (Hot Stream♨)
21
twitter4j.TwiterStream tw = ...;
Flux<String> s = Flux.<String>create(sink ->
sink.next(status.getText());
});
s.log("tweet").subscribe();
Reactor (Hot Stream♨)
22
twitter4j.TwiterStream tw = ...;
Flux<String> s = Flux.<String>create(sink ->
tw.addListener(new StatusAdapter() {
public void onStatus(Status status) {
sink.next(status.getText()); }
public void onException(Exception e) {
sink.error(e); }});
sink.onCancel(tw::shutdown);
tw.sample();
});
s.log("tweet").subscribe();
Operators in Reactor
23
• map / indexed / flatMap / flatMapMany
• collectList / collectMap / count
• concat / merge / zip / when / combineLatest
• repeat / interval
• filter / sample / take / skip
• window / windowWhile / buffer
• ...
https://projectreactor.io/docs/core/release/reference/docs/index.html#which-operator
zip
24
zip
24
zip
25
Flux<GHUser> github = findGitHubUsers("foo", "bar",
"hoge");

Flux<FBUser> facebook = findFacebookUsers("foo",
"bar", "hoge");
Flux<User> users = Flux.zip(github, facebook)
.map(tpl -> new User(tpl.getT1(), tpl.getT2()));
users.subscribe();
flatMap
26
flatMap
27
Flux<GHUser> github = findGitHubUsers("foo", "bar",
"hoge");

Flux<User> users = github.flatMap(g
-> findTweets(g)
.collectList()
.map(tweets -> new User(g, tweets)));
users.subscribe();
flatMap
28
Flux<GHUser> github = findGitHubUsers("foo", "bar",
"hoge");

Flux<User> users = github.map(g
-> findTweets(g)
.collectList()
.map(tweets -> new User(g, tweets)));
users.subscribe();
flatMap
28
Flux<GHUser> github = findGitHubUsers("foo", "bar",
"hoge");

Flux<User> users = github.map(g
-> findTweets(g)
.collectList()
.map(tweets -> new User(g, tweets)));
users.subscribe();
⚠ Can be compiled but
findTweets won't be
subscribed
flatMap
29
Flux<GHUser> github = findGitHubUsers("foo", "bar",
"hoge");
Flux<User> users = github.map(g -> {
Mono<User> u = findTweets(g)
.collectList()
.map(tweets -> new User(g, tweets));
u.subscribe();
return u;
});
users.subscribe();
This will work,
but use flatMap instead
Web Stacks in Spring 5
30
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet Stack
Spring MVC controller
31
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public String hello() {
return hello.sayHello();
}
}
Spring MVC controller
31
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public String hello() {
return hello.sayHello();
}
}
Blocking / Synchronous
Spring WebFlux controller
32
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public String hello() {
return hello.sayHello();
}
}
Spring WebFlux controller
32
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public String hello() {
return hello.sayHello();
}
}
Non-blocking / Synchronous
Spring WebFlux controller
33
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public Mono<String> hello() {
return Mono.fromCallable(hello::sayHello);
}
}
Spring WebFlux controller
33
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public Mono<String> hello() {
return Mono.fromCallable(hello::sayHello);
}
}
Non-blocking / Asynchronous
Spring WebFlux controller
33
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public Mono<String> hello() {
return Mono.fromCallable(hello::sayHello);
}
}
Non-blocking / Asynchronous
You don't need to subscribe the stream
Spring WebFlux controller
34
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public Mono<String> hello() {
return Mono.fromCallable(hello::sayHello)
.flatMap(foo::abc)
.map(bar::xyz);}
Non-blocking / Asynchronous
Spring WebFlux controller
34
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public Mono<String> hello() {
return Mono.fromCallable(hello::sayHello)
.flatMap(foo::abc)
.map(bar::xyz);}
Non-blocking / Asynchronous
Could be executed
in the other thread
Spring MVC controller
35
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public Mono<String> hello() {
return Mono.fromCallable(hello::sayHello)
.flatMap(foo::abc)
.map(bar::xyz);}
Blocking / Asynchronous
Spring MVC controller
35
@RestController
public class HelloController {
private final Hello hello;
public HelloController(Hello hello) {
this.hello = hello;
}
@GetMapping("hello")
public Mono<String> hello() {
return Mono.fromCallable(hello::sayHello)
.flatMap(foo::abc)
.map(bar::xyz);}
Blocking / Asynchronous
Async support in
Servlet 3
∞ Stream
36
@RestController
public class HelloController {
@GetMapping("hello")
public Flux<String> hello() {
Flux<String> hello = Flux.just("hello")
.delayElement(Duration.ofMillis(100));
hello.subscribe();
return hello.repeat(); // ∞ Stream
}
}
DEMO
Content Negotiation
38
Accept: text/event-stream
Accept: application/stream+json
Accept: application/json
Content Negotiation
38
Accept: text/event-stream
Accept: application/stream+json
Accept: application/json
✅ Backpressure
✅ Backpressure
❌ Backpressure
Content Negotiation
39
@GetMapping("hello")
public Flux<Message> hello() {
return Mono.just(new Message("a"))
.repeat()
.take(100)
.log("message");
}
40
$ curl -v -H "Accept: text/event-stream" localhost:8080/messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: text/event-stream
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: text/event-stream
<
data:{"text":"a"}
data:{"text":"a"}
data:{"text":"a"}
...
40
$ curl -v -H "Accept: text/event-stream" localhost:8080/messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: text/event-stream
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: text/event-stream
<
data:{"text":"a"}
data:{"text":"a"}
data:{"text":"a"}
...
INFO 48330 --- [ctor-http-nio-2] message : request(1)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
INFO 48330 --- [ctor-http-nio-2] message : request(31)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
INFO 48330 --- [ctor-http-nio-2] message : request(24)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-2] message : request(24)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-2] message : onComplete()
40
$ curl -v -H "Accept: text/event-stream" localhost:8080/messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: text/event-stream
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: text/event-stream
<
data:{"text":"a"}
data:{"text":"a"}
data:{"text":"a"}
...
INFO 48330 --- [ctor-http-nio-2] message : request(1)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
INFO 48330 --- [ctor-http-nio-2] message : request(31)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
INFO 48330 --- [ctor-http-nio-2] message : request(24)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-2] message : request(24)
INFO 48330 --- [ctor-http-nio-2] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-2] message : onComplete()
Backpressure
(FYI) In case of Servlet Stack
41
(FYI) In case of Servlet Stack
41
INFO 61528 --- [nio-8080-exec-1] message : request(1)
INFO 61528 --- [nio-8080-exec-1] message : onNext(a)
INFO 61528 --- [ MvcAsync1] message : request(1)
INFO 61528 --- [ MvcAsync1] message : onNext(a)
INFO 61528 --- [ MvcAsync2] message : request(1)
... ...
INFO 61528 --- [ MvcAsync98] message : request(1)
INFO 61528 --- [ MvcAsync98] message : onNext(a)
INFO 61528 --- [ MvcAsync99] message : request(1)
INFO 61528 --- [ MvcAsync99] message : onNext(a)
INFO 61528 --- [ MvcAsync99] message : onComplete()
(FYI) In case of Servlet Stack
41
INFO 61528 --- [nio-8080-exec-1] message : request(1)
INFO 61528 --- [nio-8080-exec-1] message : onNext(a)
INFO 61528 --- [ MvcAsync1] message : request(1)
INFO 61528 --- [ MvcAsync1] message : onNext(a)
INFO 61528 --- [ MvcAsync2] message : request(1)
... ...
INFO 61528 --- [ MvcAsync98] message : request(1)
INFO 61528 --- [ MvcAsync98] message : onNext(a)
INFO 61528 --- [ MvcAsync99] message : request(1)
INFO 61528 --- [ MvcAsync99] message : onNext(a)
INFO 61528 --- [ MvcAsync99] message : onComplete()
✅ Backpressure
42
$ curl -v -H "Accept: application/stream+json" localhost:8080/
messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: application/stream+json
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/stream+json;charset=UTF-8
<
{"text":"a"}
{"text":"a"}
{"text":"a"}
...
42
$ curl -v -H "Accept: application/stream+json" localhost:8080/
messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: application/stream+json
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/stream+json;charset=UTF-8
<
{"text":"a"}
{"text":"a"}
{"text":"a"}
...
INFO 48330 --- [ctor-http-nio-4] message : request(1)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
INFO 48330 --- [ctor-http-nio-4] message : request(31)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
INFO 48330 --- [ctor-http-nio-4] message : request(24)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-4] message : request(24)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-4] message : onComplete()
42
$ curl -v -H "Accept: application/stream+json" localhost:8080/
messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: application/stream+json
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/stream+json;charset=UTF-8
<
{"text":"a"}
{"text":"a"}
{"text":"a"}
...
INFO 48330 --- [ctor-http-nio-4] message : request(1)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
INFO 48330 --- [ctor-http-nio-4] message : request(31)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
INFO 48330 --- [ctor-http-nio-4] message : request(24)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-4] message : request(24)
INFO 48330 --- [ctor-http-nio-4] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-4] message : onComplete()
✅ Backpressure
43
$ curl -v -H "Accept: application/json" localhost:8080/messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: application/json
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/json;charset=UTF-8
<
[{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"},
{"text":"a"},{"text":"a"}]
43
$ curl -v -H "Accept: application/json" localhost:8080/messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: application/json
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/json;charset=UTF-8
<
[{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"},
{"text":"a"},{"text":"a"}]
INFO 48330 --- [ctor-http-nio-3] message : request(unbounded)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onComplete()
43
$ curl -v -H "Accept: application/json" localhost:8080/messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: application/json
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/json;charset=UTF-8
<
[{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"},
{"text":"a"},{"text":"a"}]
INFO 48330 --- [ctor-http-nio-3] message : request(unbounded)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
... ...
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onNext(a)
INFO 48330 --- [ctor-http-nio-3] message : onComplete()
❌ Backpressure
Flux -> Mono
44
@GetMapping("hello")
public Mono<List<Message>> hello() {
return Mono.just(new Message("a"))
.repeat()
.take(100)
.collectList()
.log("message");
}
Flux -> Mono
45
@GetMapping("hello")
public Mono<List<Message>> hello() {
return Mono.just(new Message("a"))
.repeat()
.take(100)
.collectList()
.log("message");
}
$ curl -v -H "Accept: application/stream+json" localhost:8080/
messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: application/stream+json
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/stream+json;charset=UTF-8
<
[{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"},
{"text":"a"},{"text":"a"}]
Flux -> Mono
45
@GetMapping("hello")
public Mono<List<Message>> hello() {
return Mono.just(new Message("a"))
.repeat()
.take(100)
.collectList()
.log("message");
}
$ curl -v -H "Accept: application/stream+json" localhost:8080/
messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: application/stream+json
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/stream+json;charset=UTF-8
<
[{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"},
{"text":"a"},{"text":"a"}]
INFO 48330 --- [ctor-http-nio-3] message : | request(1)
INFO 48330 --- [ctor-http-nio-3] message : | onNext([a, a, a, a,
a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a])
INFO 48330 --- [ctor-http-nio-3] message : | request(31)
INFO 48330 --- [ctor-http-nio-3] message : | onComplete()
Flux -> Mono
45
@GetMapping("hello")
public Mono<List<Message>> hello() {
return Mono.just(new Message("a"))
.repeat()
.take(100)
.collectList()
.log("message");
}
$ curl -v -H "Accept: application/stream+json" localhost:8080/
messages
> GET /messages HTTP/1.1
> Host: localhost:8080
> Accept: application/stream+json
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/stream+json;charset=UTF-8
<
[{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"},
{"text":"a"},{"text":"a"}]
INFO 48330 --- [ctor-http-nio-3] message : | request(1)
INFO 48330 --- [ctor-http-nio-3] message : | onNext([a, a, a, a,
a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a])
INFO 48330 --- [ctor-http-nio-3] message : | request(31)
INFO 48330 --- [ctor-http-nio-3] message : | onComplete()
❌ Backpressure
Spring WebFlux controller (Receiving Flux)
46
@RestController
public class HelloController {
@PostMapping("upper")
public Flux<String>
upper(@RequestBody Flux<String> input) {
Flux<String> output = input
.map(String::toUpperCase);
return output;
}
}
47
$ telnet localhost 8080
POST /upper HTTP/1.1
Host: localhost:8080
Transfer-Encoding: chunked
Accept: text/event-stream
Content-Type: text/plain
3
foo
HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: text/event-stream
5
data:
4
FOO
1
4
java
5
data:
5
JAVA
1
47
$ telnet localhost 8080
POST /upper HTTP/1.1
Host: localhost:8080
Transfer-Encoding: chunked
Accept: text/event-stream
Content-Type: text/plain
3
foo
HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: text/event-stream
5
data:
4
FOO
1
4
java
5
data:
5
JAVA
1
Request Body
47
$ telnet localhost 8080
POST /upper HTTP/1.1
Host: localhost:8080
Transfer-Encoding: chunked
Accept: text/event-stream
Content-Type: text/plain
3
foo
HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: text/event-stream
5
data:
4
FOO
1
4
java
5
data:
5
JAVA
1
Request Body
Response Body
Spring WebFlux controller (Receiving Flux)
48
@PostMapping("upper")
public Flux<String>
upper(@RequestBody Flux<String> input) {
Flux<String> output = input
.map(String::toUpperCase)
.flatMap(s -> Flux
.interval(Duration.ofSeconds(1))
.map(i -> s + i)
.take(3));
return output;
}
49
3
foo
HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: text/event-stream
5
data:
5
FOO0
1
5
data:
5
FOO1
1
5
data:
5
FOO2
1
DEMO
Spring MVC controller (Receiving Flux)
51
@RestController
public class HelloController {
@PostMapping("upper")
public Flux<String>
hello(@RequestBody Flux<String> input) {
Flux<String> output = input
.map(String::toUpperCase);
return output;
}
}
Spring MVC controller (Receiving Flux)
51
@RestController
public class HelloController {
@PostMapping("upper")
public Flux<String>
hello(@RequestBody Flux<String> input) {
Flux<String> output = input
.map(String::toUpperCase);
return output;
}
}
🙅
Spring MVC controller (Receiving Flux)
51
@RestController
public class HelloController {
@PostMapping("upper")
public Flux<String>
hello(@RequestBody Flux<String> input) {
Flux<String> output = input
.map(String::toUpperCase);
return output;
}
}
🙅Reactive type are supported only as
controller method return values
Broadcast stream
52
@RestController
public class HelloController {
private final Flux<String> flux;
public HelloController() {
this.flux = this.createHotStream().share();
this.flux.subscribe();
}
@GetMapping("hello")
public Flux<String> hello() {
return this.flux;
}}
Broadcast stream
52
@RestController
public class HelloController {
private final Flux<String> flux;
public HelloController() {
this.flux = this.createHotStream().share();
this.flux.subscribe();
}
@GetMapping("hello")
public Flux<String> hello() {
return this.flux;
}}
this stream is shared by all http
clients!
53
📱📱📱📱📱📱📱📱📱
📱📱📱📱📱📱📱📱📱53
📱📱📱📱📱📱📱📱📱53
🗄
📈
Devices Dashboard
HTTP POST
Server-Sent Events
∞🔄
♨
54
📱📱📱📱📱📱📱📱📱
📱📱📱📱📱📱📱📱📱54
📱📱📱📱📱📱📱📱📱54
🗄
📈
Devices Dashboard
HTTP POST
Server-Sent Events
∞🔄
📈📈📈
♨
54
📱📱📱📱📱📱📱📱📱
📱📱📱📱📱📱📱📱📱54
📱📱📱📱📱📱📱📱📱54
🗄
📈
Devices Dashboard
HTTP POST
Server-Sent Events
∞🔄
📈📈📈
♨ Shared
Web Stacks in Spring 5
55
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet Stack
Web Stacks in Spring 5
55
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet Stack
•Annotated Controller
•Function Endpoints (WebFlux.fn)
@Configuration
public class RouterConfig {
@Bean
public RouterFunctions<ServerResponse> routes() {
return route(GET("hello"), req -> {
return ServerReponse.ok()
.body(Mono.just("hello"), String.class);
});
}
}
Spring WebFlux.fn
56
@Configuration
public class RouterConfig {
@Bean
public RouterFunctions<ServerResponse> routes() {
return route(GET("hello"), req -> {
return ServerReponse.ok()
.body(Mono.just("hello"), String.class);
});
}
}
lambda
Spring WebFlux.fn
56
Spring WebFlux.fn
57
@Configuration
public class RouterConfig {
@Bean
public RouterFunctions<ServerResponse>
routes(HelloHandler helloHandler) {
return route(GET("hello"), helloHandler::hello);
}
}
Spring WebFlux.fn
58
public RouterFunctions<ServerResponse>
routes(PersonHandeler ph) {
return route(GET("person"), ph::findAll)
.andRoute(POST("person"), ph::create)
.andRoute(GET("person/{id}"), ph::findOne)
.andRoute(PUT("person/{id}"), ph::update)
.andRoute(DELETE("person/{id}"), ph::delete));
}
Spring WebFlux.fn
59
public RouterFunctions<ServerResponse>
routes(PersonHandeler ph) {
return nest(path("person"),
route(GET("/"), ph::findAll)
.andRoute(POST("/"), ph::create)
.andRoute(GET("/{id}"), ph::findOne)
.andRoute(PUT("/{id}"), ph::update)
.andRoute(DELETE("/{id}"), ph::delete)));
}
Web Stacks in Spring 5
60
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet Stack
Web Stacks in Spring 5
60
Servlet Container
Servlet API
Spring MVC
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Servlet Stack
Reactive Web Client
Reactive Web Client
61
@RestController
public class HelloController {
private final WebClient client;
public HelloController(WebClinet.Builer b) {
this.client = b.build();
}
@GetMapping("hello")
public Flux<String> hello() {
return this.client.get().uri("http://blahblah")
.retrieve().bodyToFlux(String.class);
}}
Reactive Web Client
62
Flux<User> users = webClient.get()
.uri("http://user-service")
.exchange() // => Mono<ClientResponse>
.flatMap(r -> r.bodyToFlux(User.class));
// short-cut
Flux<User> users = webClient.get()
.uri("http://user-service")
.retrieve()
.bodyToFlux(User.class);
Reactive Web Client
63
Mono<User> user = webClient.get()
.uri("http://user-service/{id}", id)
.header("X-Foo", "foo")
.retrieve().bodyToMono(User.class);
Mono<User> user = ...
Mono<Void> created = webClient.post()
.uri("http://user-service")
.body(user, User.class)
.retrieve().bodyToMono(Void.class);
From RestTemplate to WebClient
64
@Controller
public class UserController {
@GetMapping("users")
public String hello(Model model) {
List<User> users = restTemplate
.getForObject("/users", List.class);
model.addAttribute("users", users);
return "users";
}
}
From RestTemplate to WebClient
65
@Controller
public class UserController {
@GetMapping("users")
public String hello(Model model) {
Flux<User> users = client.get().uri("/users")
.retrieve().bodyToFlux(String.class);
model.addAttribute("users", users);
return "users";
}
}
66
<html>
<body>
<ul>
<li data-th-each="user : ${user}">[[${user}]]</li>
</ul>
</body>
</html>
66
<html>
<body>
<ul>
<li data-th-each="user : ${user}">[[${user}]]</li>
</ul>
</body>
</html>
😀 Spring WebFlux
66
<html>
<body>
<ul>
<li data-th-each="user : ${user}">[[${user}]]</li>
</ul>
</body>
</html>
😀 Spring WebFlux
😨 Spring MVC
From RestTemplate to WebClient (Spring MVC)
67
@Controller
public class UserController {
@GetMapping("users")
public Mono<String> hello(Model model) {
Flux<User> users = client.get().uri("/users")
.retrieve().bodyToFlux(String.class);
users.collectList().map(x -> {
model.addAttribute("users", x);
return "users";
});
}
From RestTemplate to WebClient (Spring MVC)
67
@Controller
public class UserController {
@GetMapping("users")
public Mono<String> hello(Model model) {
Flux<User> users = client.get().uri("/users")
.retrieve().bodyToFlux(String.class);
users.collectList().map(x -> {
model.addAttribute("users", x);
return "users";
});
}
😀 Spring MVC
From RestTemplate to WebClient (Spring MVC)
68
@Controller
public class UserController {
@GetMapping("users")
public Mono<String> hello(Model model) {
Flux<User> users = ...;
Mono<Sting> foo = ...;
return Mono.zip(user.collectList(), foo)
   .map(tpl -> {
model.addAttribute("users", tpl.getT1());
model.addAttribute("foo", tpl.getT2());
return "users";
});}}
69
String url = "http://httpbin.org/delay/1";
@GetMapping("hello")
public Mono<String> hello() {
Mono<String> mono = Mono.just(restTemplate
.getForObject(url));
return mono;
}
⚠ Don't block the thread in WebFlux!
69
String url = "http://httpbin.org/delay/1";
@GetMapping("hello")
public Mono<String> hello() {
Mono<String> mono = Mono.just(restTemplate
.getForObject(url));
return mono;
}
⚠ Don't block the thread in WebFlux!
69
String url = "http://httpbin.org/delay/1";
@GetMapping("hello")
public Mono<String> hello() {
Mono<String> mono = Mono.just(restTemplate
.getForObject(url));
return mono;
} 😠 Blocking!
⚠ Don't block the thread in WebFlux!
70
String url = "http://httpbin.org/delay/1";
@GetMapping("hello")
public Mono<String> hello() {
Mono<String> mono = Mono
.fromCallable(() ->restTemplate.getForObject(url))
.subscribeOn(Schedulers.elastic());
return mono;
}
⚠ Don't block the thread in WebFlux!
70
String url = "http://httpbin.org/delay/1";
@GetMapping("hello")
public Mono<String> hello() {
Mono<String> mono = Mono
.fromCallable(() ->restTemplate.getForObject(url))
.subscribeOn(Schedulers.elastic());
return mono;
} Switch the execution context
71
Concurrency
Throughput [trans / sec]
Core i7 2.7 GHz
4 Core x HT
Reactive Support in Spring Projects
72
Spring Data
Reactive Stack
Netty, Servlet 3.1+,
Undertow
Reactive Streams
Spring WebFlux
Spring Security
Thymeleaf
Spring Data Kay
73
Reactive support for
• Redis
• MongoDB
• Couchbase
• Cassandra
Infinite streams from the database with @Tailable
Reactive Non-Blocking Data Access
74
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)
// ...
}
Tailable Cursor Support for MongoDB
75
public interface MessageRepository
extends ReactiveMongoRepository<Message,String>
{
@Tailable
Flux<Message>
findByUpdatedAtGreaterThan(Instant target);
}
Broadcast updated messages in MongoDB
76
@RestController
public class HelloController {
private final Flux<Message> messages;
public HelloController(MessageRepository repo) {
this.messages = repo
.findByUpdatedAtGreaterThan(Instant.now())
.share();
this.messages.subscribe();
}
@GetMapping("messages")
public Flux<Message> messages() {
return this.messages;
}}
But, but, JDBC is blocking .... 😭
77
But, but, JDBC is blocking .... 😭
77
Let's see what will happen in next Java
But, but, JDBC is blocking .... 😭
77
Let's see what will happen in next Java
https://static.rainfocus.com/oracle/oow17/sess/1491948952321001dm4m/PF/JavaOne%2017%20-
%20CON1491_1506954898905001IipH.pdf
java.sql2
78
http://cr.openjdk.java.net/~lancea/apidoc/java/sql2/package-summary.html
java.sql2
78
http://cr.openjdk.java.net/~lancea/apidoc/java/sql2/package-summary.html
😢 Does not seem to support
Reactive Streams (j.u.c.Flow)
Spring Security Reactive
79
@Bean
public SecurityWebFilterChain
springWebFilterChain(HttpSecurity http) {
return http.authorizeExchange()
.pathMatchers("/v2/**").hasRole("ADMIN")
.and().httpBasic().and().build();
}
@Bean
public MapUserDetailsRepository userDetailsRepository() {
return new MapUserDetailsRepository(...);
}
Thymeleaf 3.0 reactive support
80
• "full mode"
• "chunked mode"

=> Progressive rendering. Good for large pages
• "data-driven mode" 

=> Rendering template fragments as Server-Sent Events

• https://github.com/thymeleaf/thymeleaf-spring/issues/132
• https://github.com/spring-projects/spring-boot/issues/8124
• https://speakerdeck.com/dfernandez/o-2017-getting-thymeleaf-ready-
for-spring-5-and-reactive?slide=18
transfer-encoding: chunked
Data-driven mode
81
@GetMapping("users")
public String hello(Model model) {
Flux<User> users = userService.findAll();
ReactiveDataDriverContextVariable v
= new ReactiveDataDriverContextVariable(users, 1);
model.addAttribute("users", v);
return "users";
}
DEMO
Reactive Application Patterns (as of 2017)
83
Reactive Application Patterns (as of 2017)
83
Spring WebFluxSpring WebFlux
Frontend Backend
HTTP NoSQL
WebClient Spring Data
Reactive Application Patterns (as of 2017)
84
Spring MVCSpring WebFlux
Frontend Backend
HTTP RDB
JDBC
WebClient
Reactive Application Patterns (as of 2017)
85
Spring MVCSpring MVC
Frontend Backend
HTTP RDB
JDBC
WebClient
Spring Cloud Gateway
86
A Gateway built on Spring Framework 5.0 and Spring
Boot 2.0 providing routing and more
http://cloud.spring.io/spring-cloud-gateway/
http://cloud.spring.io/spring-cloud-gateway/2.0.x/single/
spring-cloud-gateway.html
Start Spring 5 & Spring Boot 2
87
Servlet Stack ⇄ Reactive Stack
88
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Reactive Stack
Servlet Stack
Servlet Stack ⇄ Reactive Stack
89
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.ipc</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Reactive Stack
Servlet Stack
+
WebClient
Thanks!
90
Resources
• Servlet vs Reactive Stacks in Five Use Cases
• Spring Boot 2 0 Web Applications
• Spring Framework 5: Themes & Trends
• Why Spring ❤ Kotlin

Contenu connexe

Tendances

Reactive Programming in Java and Spring Framework 5
Reactive Programming in Java and Spring Framework 5Reactive Programming in Java and Spring Framework 5
Reactive Programming in Java and Spring Framework 5Richard Langlois P. Eng.
 
Introduction to Spring webflux
Introduction to Spring webfluxIntroduction to Spring webflux
Introduction to Spring webfluxKnoldus Inc.
 
[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive SpringKnoldus Inc.
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJSBrainhub
 
Java 8 lambda expressions
Java 8 lambda expressionsJava 8 lambda expressions
Java 8 lambda expressionsLogan Chien
 
NET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptxNET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptxpetabridge
 
Reactive programming
Reactive programmingReactive programming
Reactive programmingSUDIP GHOSH
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJosé Paumard
 
Microservices with Spring 5 Webflux - jProfessionals
Microservices  with Spring 5 Webflux - jProfessionalsMicroservices  with Spring 5 Webflux - jProfessionals
Microservices with Spring 5 Webflux - jProfessionalsTrayan Iliev
 
C#次世代非同期処理概観 - Task vs Reactive Extensions
C#次世代非同期処理概観 - Task vs Reactive ExtensionsC#次世代非同期処理概観 - Task vs Reactive Extensions
C#次世代非同期処理概観 - Task vs Reactive ExtensionsYoshifumi Kawai
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
Reactive Programming In Java Using: Project Reactor
Reactive Programming In Java Using: Project ReactorReactive Programming In Java Using: Project Reactor
Reactive Programming In Java Using: Project ReactorKnoldus Inc.
 
Java nio ( new io )
Java nio ( new io )Java nio ( new io )
Java nio ( new io )Jemin Patel
 
イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化Gosuke Miyashita
 
What's new in Spring Batch 5
What's new in Spring Batch 5What's new in Spring Batch 5
What's new in Spring Batch 5ikeyat
 
Developing RESTful Web APIs with Python, Flask and MongoDB
Developing RESTful Web APIs with Python, Flask and MongoDBDeveloping RESTful Web APIs with Python, Flask and MongoDB
Developing RESTful Web APIs with Python, Flask and MongoDBNicola Iarocci
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOPDzmitry Naskou
 

Tendances (20)

Reactive Programming in Java and Spring Framework 5
Reactive Programming in Java and Spring Framework 5Reactive Programming in Java and Spring Framework 5
Reactive Programming in Java and Spring Framework 5
 
Introduction to Spring webflux
Introduction to Spring webfluxIntroduction to Spring webflux
Introduction to Spring webflux
 
[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJS
 
Java 8 lambda expressions
Java 8 lambda expressionsJava 8 lambda expressions
Java 8 lambda expressions
 
NET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptxNET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptx
 
Reactive programming
Reactive programmingReactive programming
Reactive programming
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
 
Microservices with Spring 5 Webflux - jProfessionals
Microservices  with Spring 5 Webflux - jProfessionalsMicroservices  with Spring 5 Webflux - jProfessionals
Microservices with Spring 5 Webflux - jProfessionals
 
C#次世代非同期処理概観 - Task vs Reactive Extensions
C#次世代非同期処理概観 - Task vs Reactive ExtensionsC#次世代非同期処理概観 - Task vs Reactive Extensions
C#次世代非同期処理概観 - Task vs Reactive Extensions
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
Reactive Programming In Java Using: Project Reactor
Reactive Programming In Java Using: Project ReactorReactive Programming In Java Using: Project Reactor
Reactive Programming In Java Using: Project Reactor
 
Java nio ( new io )
Java nio ( new io )Java nio ( new io )
Java nio ( new io )
 
Introduction to JavaFX
Introduction to JavaFXIntroduction to JavaFX
Introduction to JavaFX
 
イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化
 
What's new in Spring Batch 5
What's new in Spring Batch 5What's new in Spring Batch 5
What's new in Spring Batch 5
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Developing RESTful Web APIs with Python, Flask and MongoDB
Developing RESTful Web APIs with Python, Flask and MongoDBDeveloping RESTful Web APIs with Python, Flask and MongoDB
Developing RESTful Web APIs with Python, Flask and MongoDB
 
Spring Security
Spring SecuritySpring Security
Spring Security
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
 

Similaire à Introduction to Spring WebFlux #jsug #sf_a1

FrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftFrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftChris Bailey
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseAlex Derkach
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionChristian Panadero
 
Ruby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVCRuby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVCSimone Chiaretta
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomyDongmin Yu
 
SoCal Code Camp 2015: An introduction to Java 8
SoCal Code Camp 2015: An introduction to Java 8SoCal Code Camp 2015: An introduction to Java 8
SoCal Code Camp 2015: An introduction to Java 8Chaitanya Ganoo
 
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018Loiane Groner
 
Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001Sven Ruppert
 
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConfFull-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConfLoiane Groner
 
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java GirlFull-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java GirlLoiane Groner
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularLoiane Groner
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuVMware Tanzu
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020Matt Raible
 

Similaire à Introduction to Spring WebFlux #jsug #sf_a1 (20)

Arquitecturas de microservicios - Medianet Software
Arquitecturas de microservicios   -  Medianet SoftwareArquitecturas de microservicios   -  Medianet Software
Arquitecturas de microservicios - Medianet Software
 
FrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftFrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) Swift
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & Couchbase
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca edition
 
Hexagonal architecture in PHP
Hexagonal architecture in PHPHexagonal architecture in PHP
Hexagonal architecture in PHP
 
groovy & grails - lecture 13
groovy & grails - lecture 13groovy & grails - lecture 13
groovy & grails - lecture 13
 
Spring 4 Web App
Spring 4 Web AppSpring 4 Web App
Spring 4 Web App
 
Ruby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVCRuby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVC
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
 
SoCal Code Camp 2015: An introduction to Java 8
SoCal Code Camp 2015: An introduction to Java 8SoCal Code Camp 2015: An introduction to Java 8
SoCal Code Camp 2015: An introduction to Java 8
 
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
 
Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001
 
Openshift31-tech.ppt
Openshift31-tech.pptOpenshift31-tech.ppt
Openshift31-tech.ppt
 
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConfFull-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
 
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java GirlFull-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + Angular
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFu
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
 
RxJava Applied
RxJava AppliedRxJava Applied
RxJava Applied
 

Plus de Toshiaki Maki

From Spring Boot 2.2 to Spring Boot 2.3 #jsug
From Spring Boot 2.2 to Spring Boot 2.3 #jsugFrom Spring Boot 2.2 to Spring Boot 2.3 #jsug
From Spring Boot 2.2 to Spring Boot 2.3 #jsugToshiaki Maki
 
Concourse x Spinnaker #concourse_tokyo
Concourse x Spinnaker #concourse_tokyoConcourse x Spinnaker #concourse_tokyo
Concourse x Spinnaker #concourse_tokyoToshiaki Maki
 
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1t
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1tServerless with Spring Cloud Function, Knative and riff #SpringOneTour #s1t
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1tToshiaki Maki
 
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1Toshiaki Maki
 
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1Toshiaki Maki
 
Spring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerSpring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerToshiaki Maki
 
Open Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjpOpen Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjpToshiaki Maki
 
Spring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugSpring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugToshiaki Maki
 
BOSH / CF Deployment in modern ways #cf_tokyo
BOSH / CF Deployment in modern ways #cf_tokyoBOSH / CF Deployment in modern ways #cf_tokyo
BOSH / CF Deployment in modern ways #cf_tokyoToshiaki Maki
 
Why PCF is the best platform for Spring Boot
Why PCF is the best platform for Spring BootWhy PCF is the best platform for Spring Boot
Why PCF is the best platform for Spring BootToshiaki Maki
 
Zipkin Components #zipkin_jp
Zipkin Components #zipkin_jpZipkin Components #zipkin_jp
Zipkin Components #zipkin_jpToshiaki Maki
 
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07Toshiaki Maki
 
Spring Framework 5.0による Reactive Web Application #JavaDayTokyo
Spring Framework 5.0による Reactive Web Application #JavaDayTokyoSpring Framework 5.0による Reactive Web Application #JavaDayTokyo
Spring Framework 5.0による Reactive Web Application #JavaDayTokyoToshiaki Maki
 
実例で学ぶ、明日から使えるSpring Boot Tips #jsug
実例で学ぶ、明日から使えるSpring Boot Tips #jsug実例で学ぶ、明日から使えるSpring Boot Tips #jsug
実例で学ぶ、明日から使えるSpring Boot Tips #jsugToshiaki Maki
 
Spring ❤️ Kotlin #jjug
Spring ❤️ Kotlin #jjugSpring ❤️ Kotlin #jjug
Spring ❤️ Kotlin #jjugToshiaki Maki
 
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3Toshiaki Maki
 
Managing your Docker image continuously with Concourse CI
Managing your Docker image continuously with Concourse CIManaging your Docker image continuously with Concourse CI
Managing your Docker image continuously with Concourse CIToshiaki Maki
 
Data Microservices with Spring Cloud Stream, Task, and Data Flow #jsug #spri...
Data Microservices with Spring Cloud Stream, Task,  and Data Flow #jsug #spri...Data Microservices with Spring Cloud Stream, Task,  and Data Flow #jsug #spri...
Data Microservices with Spring Cloud Stream, Task, and Data Flow #jsug #spri...Toshiaki Maki
 
Short Lived Tasks in Cloud Foundry #cfdtokyo
Short Lived Tasks in Cloud Foundry #cfdtokyoShort Lived Tasks in Cloud Foundry #cfdtokyo
Short Lived Tasks in Cloud Foundry #cfdtokyoToshiaki Maki
 
今すぐ始めるCloud Foundry #hackt #hackt_k
今すぐ始めるCloud Foundry #hackt #hackt_k今すぐ始めるCloud Foundry #hackt #hackt_k
今すぐ始めるCloud Foundry #hackt #hackt_kToshiaki Maki
 

Plus de Toshiaki Maki (20)

From Spring Boot 2.2 to Spring Boot 2.3 #jsug
From Spring Boot 2.2 to Spring Boot 2.3 #jsugFrom Spring Boot 2.2 to Spring Boot 2.3 #jsug
From Spring Boot 2.2 to Spring Boot 2.3 #jsug
 
Concourse x Spinnaker #concourse_tokyo
Concourse x Spinnaker #concourse_tokyoConcourse x Spinnaker #concourse_tokyo
Concourse x Spinnaker #concourse_tokyo
 
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1t
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1tServerless with Spring Cloud Function, Knative and riff #SpringOneTour #s1t
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1t
 
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
 
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1
 
Spring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerSpring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & Micrometer
 
Open Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjpOpen Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjp
 
Spring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugSpring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsug
 
BOSH / CF Deployment in modern ways #cf_tokyo
BOSH / CF Deployment in modern ways #cf_tokyoBOSH / CF Deployment in modern ways #cf_tokyo
BOSH / CF Deployment in modern ways #cf_tokyo
 
Why PCF is the best platform for Spring Boot
Why PCF is the best platform for Spring BootWhy PCF is the best platform for Spring Boot
Why PCF is the best platform for Spring Boot
 
Zipkin Components #zipkin_jp
Zipkin Components #zipkin_jpZipkin Components #zipkin_jp
Zipkin Components #zipkin_jp
 
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
 
Spring Framework 5.0による Reactive Web Application #JavaDayTokyo
Spring Framework 5.0による Reactive Web Application #JavaDayTokyoSpring Framework 5.0による Reactive Web Application #JavaDayTokyo
Spring Framework 5.0による Reactive Web Application #JavaDayTokyo
 
実例で学ぶ、明日から使えるSpring Boot Tips #jsug
実例で学ぶ、明日から使えるSpring Boot Tips #jsug実例で学ぶ、明日から使えるSpring Boot Tips #jsug
実例で学ぶ、明日から使えるSpring Boot Tips #jsug
 
Spring ❤️ Kotlin #jjug
Spring ❤️ Kotlin #jjugSpring ❤️ Kotlin #jjug
Spring ❤️ Kotlin #jjug
 
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
 
Managing your Docker image continuously with Concourse CI
Managing your Docker image continuously with Concourse CIManaging your Docker image continuously with Concourse CI
Managing your Docker image continuously with Concourse CI
 
Data Microservices with Spring Cloud Stream, Task, and Data Flow #jsug #spri...
Data Microservices with Spring Cloud Stream, Task,  and Data Flow #jsug #spri...Data Microservices with Spring Cloud Stream, Task,  and Data Flow #jsug #spri...
Data Microservices with Spring Cloud Stream, Task, and Data Flow #jsug #spri...
 
Short Lived Tasks in Cloud Foundry #cfdtokyo
Short Lived Tasks in Cloud Foundry #cfdtokyoShort Lived Tasks in Cloud Foundry #cfdtokyo
Short Lived Tasks in Cloud Foundry #cfdtokyo
 
今すぐ始めるCloud Foundry #hackt #hackt_k
今すぐ始めるCloud Foundry #hackt #hackt_k今すぐ始めるCloud Foundry #hackt #hackt_k
今すぐ始めるCloud Foundry #hackt #hackt_k
 

Dernier

Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...apidays
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Zilliz
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbuapidays
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfOverkill Security
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024The Digital Insurer
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 

Dernier (20)

Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 

Introduction to Spring WebFlux #jsug #sf_a1

  • 1. 1 Introduction to Spring WebFlux 2017-11-24 Toshiaki Maki (@making) #jsug #sf_a1
  • 2. Who am I ? 2 Toshiaki Maki (@making) https://blog.ik.am Sr. Solutions Architect @Pivotal Japan Spring Framework 💖 Cloud Foundry 💖
  • 5. ❓How many threads are this app using? 5
  • 6. ❓How many threads are this app using? 5 1. 200 - 2. 100 - 200 3. 50 - 100 4. 10 - 50 5. 1 - 10
  • 7. 6
  • 8. Web Stacks in Spring 5 7 Servlet Container Servlet API Spring MVC Servlet Stack
  • 9. Web Stacks in Spring 5 7 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet Stack
  • 10. Web Stacks in Spring 5 7 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet StackBlocking
  • 11. Web Stacks in Spring 5 7 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet StackBlocking
  • 12. Web Stacks in Spring 5 7 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet StackBlocking Non-Blocking
  • 13. Web Stacks in Spring 5 7 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet StackBlocking Non-Blocking
  • 15. 9 Reactive Stack 🔄 Thread 🔄 Thread 🔄 Thread 🔄 Thread
  • 16. ❓Why are we introducing Spring WebFlux? 10
  • 17. ❓Why are we introducing Spring WebFlux? 10 The goal of Spring WebFlux is to offer Spring developers a non-blocking event-loop style programming model similar to node.js.
  • 18. the non-blocking async programming model is more efficient for latency-sensitive workloads. – Blocking threads consume resources – mobile applications and interconnected microservices ❓Why are we introducing Spring WebFlux? 10 The goal of Spring WebFlux is to offer Spring developers a non-blocking event-loop style programming model similar to node.js.
  • 19. Web Stacks in Spring 5 11 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet Stack
  • 25. 13
  • 26. 13
  • 28. 5 Flux<T> is a Publisher<T> for 0..n elements
  • 30. 7 Mono<T> is a Publisher<T> for 0..1 element
  • 31. Reactor 18 Flux<String> s = Flux .just("a", "b", "c", "d") .map(String::toUpperCase); s.log("demo").subscribe();
  • 32. Reactor 18 Flux<String> s = Flux .just("a", "b", "c", "d") .map(String::toUpperCase); s.log("demo").subscribe(); Need to be subscribed!
  • 33. Reactor 18 Flux<String> s = Flux .just("a", "b", "c", "d") .map(String::toUpperCase); s.log("demo").subscribe(); Need to be subscribed! 00:58:33.902 [main] INFO demo - | request(unbounded) 00:58:33.903 [main] INFO demo - | onNext(A) 00:58:33.903 [main] INFO demo - | onNext(B) 00:58:33.903 [main] INFO demo - | onNext(C) 00:58:33.903 [main] INFO demo - | onNext(D) 00:58:33.903 [main] INFO demo - | onComplete()
  • 34. Reactor 19 Flux<String> s = Flux .just("a", "b", "c", "d") .map(String::toUpperCase) .delayElements(Duration.ofSeconds(1)); s.log("demo").subscribe();
  • 35. Reactor 19 Flux<String> s = Flux .just("a", "b", "c", "d") .map(String::toUpperCase) .delayElements(Duration.ofSeconds(1)); s.log("demo").subscribe(); 00:59:42.949 [main] INFO demo - request(unbounded) 00:59:43.992 [parallel-1] INFO demo - onNext(A) 00:59:44.994 [parallel-2] INFO demo - onNext(B) 00:59:45.997 [parallel-3] INFO demo - onNext(C) 00:59:46.999 [parallel-4] INFO demo - onNext(D) 00:59:47.001 [parallel-4] INFO demo - onComplete()
  • 36. Reactor (Hot Stream♨) 20 Flux<String> s = Flux.<String>create(sink -> sink.next(...); }); s.log("demo").subscribe();
  • 37. Reactor (Hot Stream♨) 21 twitter4j.TwiterStream tw = ...; Flux<String> s = Flux.<String>create(sink -> sink.next(status.getText()); }); s.log("tweet").subscribe();
  • 38. Reactor (Hot Stream♨) 22 twitter4j.TwiterStream tw = ...; Flux<String> s = Flux.<String>create(sink -> tw.addListener(new StatusAdapter() { public void onStatus(Status status) { sink.next(status.getText()); } public void onException(Exception e) { sink.error(e); }}); sink.onCancel(tw::shutdown); tw.sample(); }); s.log("tweet").subscribe();
  • 39. Operators in Reactor 23 • map / indexed / flatMap / flatMapMany • collectList / collectMap / count • concat / merge / zip / when / combineLatest • repeat / interval • filter / sample / take / skip • window / windowWhile / buffer • ... https://projectreactor.io/docs/core/release/reference/docs/index.html#which-operator
  • 42. zip 25 Flux<GHUser> github = findGitHubUsers("foo", "bar", "hoge");
 Flux<FBUser> facebook = findFacebookUsers("foo", "bar", "hoge"); Flux<User> users = Flux.zip(github, facebook) .map(tpl -> new User(tpl.getT1(), tpl.getT2())); users.subscribe();
  • 44. flatMap 27 Flux<GHUser> github = findGitHubUsers("foo", "bar", "hoge");
 Flux<User> users = github.flatMap(g -> findTweets(g) .collectList() .map(tweets -> new User(g, tweets))); users.subscribe();
  • 45. flatMap 28 Flux<GHUser> github = findGitHubUsers("foo", "bar", "hoge");
 Flux<User> users = github.map(g -> findTweets(g) .collectList() .map(tweets -> new User(g, tweets))); users.subscribe();
  • 46. flatMap 28 Flux<GHUser> github = findGitHubUsers("foo", "bar", "hoge");
 Flux<User> users = github.map(g -> findTweets(g) .collectList() .map(tweets -> new User(g, tweets))); users.subscribe(); ⚠ Can be compiled but findTweets won't be subscribed
  • 47. flatMap 29 Flux<GHUser> github = findGitHubUsers("foo", "bar", "hoge"); Flux<User> users = github.map(g -> { Mono<User> u = findTweets(g) .collectList() .map(tweets -> new User(g, tweets)); u.subscribe(); return u; }); users.subscribe(); This will work, but use flatMap instead
  • 48. Web Stacks in Spring 5 30 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet Stack
  • 49. Spring MVC controller 31 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public String hello() { return hello.sayHello(); } }
  • 50. Spring MVC controller 31 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public String hello() { return hello.sayHello(); } } Blocking / Synchronous
  • 51. Spring WebFlux controller 32 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public String hello() { return hello.sayHello(); } }
  • 52. Spring WebFlux controller 32 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public String hello() { return hello.sayHello(); } } Non-blocking / Synchronous
  • 53. Spring WebFlux controller 33 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public Mono<String> hello() { return Mono.fromCallable(hello::sayHello); } }
  • 54. Spring WebFlux controller 33 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public Mono<String> hello() { return Mono.fromCallable(hello::sayHello); } } Non-blocking / Asynchronous
  • 55. Spring WebFlux controller 33 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public Mono<String> hello() { return Mono.fromCallable(hello::sayHello); } } Non-blocking / Asynchronous You don't need to subscribe the stream
  • 56. Spring WebFlux controller 34 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public Mono<String> hello() { return Mono.fromCallable(hello::sayHello) .flatMap(foo::abc) .map(bar::xyz);} Non-blocking / Asynchronous
  • 57. Spring WebFlux controller 34 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public Mono<String> hello() { return Mono.fromCallable(hello::sayHello) .flatMap(foo::abc) .map(bar::xyz);} Non-blocking / Asynchronous Could be executed in the other thread
  • 58. Spring MVC controller 35 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public Mono<String> hello() { return Mono.fromCallable(hello::sayHello) .flatMap(foo::abc) .map(bar::xyz);} Blocking / Asynchronous
  • 59. Spring MVC controller 35 @RestController public class HelloController { private final Hello hello; public HelloController(Hello hello) { this.hello = hello; } @GetMapping("hello") public Mono<String> hello() { return Mono.fromCallable(hello::sayHello) .flatMap(foo::abc) .map(bar::xyz);} Blocking / Asynchronous Async support in Servlet 3
  • 60. ∞ Stream 36 @RestController public class HelloController { @GetMapping("hello") public Flux<String> hello() { Flux<String> hello = Flux.just("hello") .delayElement(Duration.ofMillis(100)); hello.subscribe(); return hello.repeat(); // ∞ Stream } }
  • 61. DEMO
  • 62. Content Negotiation 38 Accept: text/event-stream Accept: application/stream+json Accept: application/json
  • 63. Content Negotiation 38 Accept: text/event-stream Accept: application/stream+json Accept: application/json ✅ Backpressure ✅ Backpressure ❌ Backpressure
  • 64. Content Negotiation 39 @GetMapping("hello") public Flux<Message> hello() { return Mono.just(new Message("a")) .repeat() .take(100) .log("message"); }
  • 65. 40 $ curl -v -H "Accept: text/event-stream" localhost:8080/messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: text/event-stream > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: text/event-stream < data:{"text":"a"} data:{"text":"a"} data:{"text":"a"} ...
  • 66. 40 $ curl -v -H "Accept: text/event-stream" localhost:8080/messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: text/event-stream > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: text/event-stream < data:{"text":"a"} data:{"text":"a"} data:{"text":"a"} ... INFO 48330 --- [ctor-http-nio-2] message : request(1) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) INFO 48330 --- [ctor-http-nio-2] message : request(31) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-2] message : onNext(a) INFO 48330 --- [ctor-http-nio-2] message : request(24) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-2] message : request(24) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-2] message : onComplete()
  • 67. 40 $ curl -v -H "Accept: text/event-stream" localhost:8080/messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: text/event-stream > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: text/event-stream < data:{"text":"a"} data:{"text":"a"} data:{"text":"a"} ... INFO 48330 --- [ctor-http-nio-2] message : request(1) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) INFO 48330 --- [ctor-http-nio-2] message : request(31) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-2] message : onNext(a) INFO 48330 --- [ctor-http-nio-2] message : request(24) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-2] message : request(24) INFO 48330 --- [ctor-http-nio-2] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-2] message : onComplete() Backpressure
  • 68. (FYI) In case of Servlet Stack 41
  • 69. (FYI) In case of Servlet Stack 41 INFO 61528 --- [nio-8080-exec-1] message : request(1) INFO 61528 --- [nio-8080-exec-1] message : onNext(a) INFO 61528 --- [ MvcAsync1] message : request(1) INFO 61528 --- [ MvcAsync1] message : onNext(a) INFO 61528 --- [ MvcAsync2] message : request(1) ... ... INFO 61528 --- [ MvcAsync98] message : request(1) INFO 61528 --- [ MvcAsync98] message : onNext(a) INFO 61528 --- [ MvcAsync99] message : request(1) INFO 61528 --- [ MvcAsync99] message : onNext(a) INFO 61528 --- [ MvcAsync99] message : onComplete()
  • 70. (FYI) In case of Servlet Stack 41 INFO 61528 --- [nio-8080-exec-1] message : request(1) INFO 61528 --- [nio-8080-exec-1] message : onNext(a) INFO 61528 --- [ MvcAsync1] message : request(1) INFO 61528 --- [ MvcAsync1] message : onNext(a) INFO 61528 --- [ MvcAsync2] message : request(1) ... ... INFO 61528 --- [ MvcAsync98] message : request(1) INFO 61528 --- [ MvcAsync98] message : onNext(a) INFO 61528 --- [ MvcAsync99] message : request(1) INFO 61528 --- [ MvcAsync99] message : onNext(a) INFO 61528 --- [ MvcAsync99] message : onComplete() ✅ Backpressure
  • 71. 42 $ curl -v -H "Accept: application/stream+json" localhost:8080/ messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: application/stream+json > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: application/stream+json;charset=UTF-8 < {"text":"a"} {"text":"a"} {"text":"a"} ...
  • 72. 42 $ curl -v -H "Accept: application/stream+json" localhost:8080/ messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: application/stream+json > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: application/stream+json;charset=UTF-8 < {"text":"a"} {"text":"a"} {"text":"a"} ... INFO 48330 --- [ctor-http-nio-4] message : request(1) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) INFO 48330 --- [ctor-http-nio-4] message : request(31) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-4] message : onNext(a) INFO 48330 --- [ctor-http-nio-4] message : request(24) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-4] message : request(24) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-4] message : onComplete()
  • 73. 42 $ curl -v -H "Accept: application/stream+json" localhost:8080/ messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: application/stream+json > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: application/stream+json;charset=UTF-8 < {"text":"a"} {"text":"a"} {"text":"a"} ... INFO 48330 --- [ctor-http-nio-4] message : request(1) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) INFO 48330 --- [ctor-http-nio-4] message : request(31) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-4] message : onNext(a) INFO 48330 --- [ctor-http-nio-4] message : request(24) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-4] message : request(24) INFO 48330 --- [ctor-http-nio-4] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-4] message : onComplete() ✅ Backpressure
  • 74. 43 $ curl -v -H "Accept: application/json" localhost:8080/messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: application/json > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: application/json;charset=UTF-8 < [{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"}, {"text":"a"},{"text":"a"}]
  • 75. 43 $ curl -v -H "Accept: application/json" localhost:8080/messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: application/json > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: application/json;charset=UTF-8 < [{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"}, {"text":"a"},{"text":"a"}] INFO 48330 --- [ctor-http-nio-3] message : request(unbounded) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onComplete()
  • 76. 43 $ curl -v -H "Accept: application/json" localhost:8080/messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: application/json > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: application/json;charset=UTF-8 < [{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"}, {"text":"a"},{"text":"a"}] INFO 48330 --- [ctor-http-nio-3] message : request(unbounded) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) ... ... INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onNext(a) INFO 48330 --- [ctor-http-nio-3] message : onComplete() ❌ Backpressure
  • 77. Flux -> Mono 44 @GetMapping("hello") public Mono<List<Message>> hello() { return Mono.just(new Message("a")) .repeat() .take(100) .collectList() .log("message"); }
  • 78. Flux -> Mono 45 @GetMapping("hello") public Mono<List<Message>> hello() { return Mono.just(new Message("a")) .repeat() .take(100) .collectList() .log("message"); } $ curl -v -H "Accept: application/stream+json" localhost:8080/ messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: application/stream+json > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: application/stream+json;charset=UTF-8 < [{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"}, {"text":"a"},{"text":"a"}]
  • 79. Flux -> Mono 45 @GetMapping("hello") public Mono<List<Message>> hello() { return Mono.just(new Message("a")) .repeat() .take(100) .collectList() .log("message"); } $ curl -v -H "Accept: application/stream+json" localhost:8080/ messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: application/stream+json > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: application/stream+json;charset=UTF-8 < [{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"}, {"text":"a"},{"text":"a"}] INFO 48330 --- [ctor-http-nio-3] message : | request(1) INFO 48330 --- [ctor-http-nio-3] message : | onNext([a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a]) INFO 48330 --- [ctor-http-nio-3] message : | request(31) INFO 48330 --- [ctor-http-nio-3] message : | onComplete()
  • 80. Flux -> Mono 45 @GetMapping("hello") public Mono<List<Message>> hello() { return Mono.just(new Message("a")) .repeat() .take(100) .collectList() .log("message"); } $ curl -v -H "Accept: application/stream+json" localhost:8080/ messages > GET /messages HTTP/1.1 > Host: localhost:8080 > Accept: application/stream+json > < HTTP/1.1 200 OK < transfer-encoding: chunked < Content-Type: application/stream+json;charset=UTF-8 < [{"text":"a"},{"text":"a"},...,{"text":"a"},{"text":"a"}, {"text":"a"},{"text":"a"}] INFO 48330 --- [ctor-http-nio-3] message : | request(1) INFO 48330 --- [ctor-http-nio-3] message : | onNext([a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a]) INFO 48330 --- [ctor-http-nio-3] message : | request(31) INFO 48330 --- [ctor-http-nio-3] message : | onComplete() ❌ Backpressure
  • 81. Spring WebFlux controller (Receiving Flux) 46 @RestController public class HelloController { @PostMapping("upper") public Flux<String> upper(@RequestBody Flux<String> input) { Flux<String> output = input .map(String::toUpperCase); return output; } }
  • 82. 47 $ telnet localhost 8080 POST /upper HTTP/1.1 Host: localhost:8080 Transfer-Encoding: chunked Accept: text/event-stream Content-Type: text/plain 3 foo HTTP/1.1 200 OK transfer-encoding: chunked Content-Type: text/event-stream 5 data: 4 FOO 1 4 java 5 data: 5 JAVA 1
  • 83. 47 $ telnet localhost 8080 POST /upper HTTP/1.1 Host: localhost:8080 Transfer-Encoding: chunked Accept: text/event-stream Content-Type: text/plain 3 foo HTTP/1.1 200 OK transfer-encoding: chunked Content-Type: text/event-stream 5 data: 4 FOO 1 4 java 5 data: 5 JAVA 1 Request Body
  • 84. 47 $ telnet localhost 8080 POST /upper HTTP/1.1 Host: localhost:8080 Transfer-Encoding: chunked Accept: text/event-stream Content-Type: text/plain 3 foo HTTP/1.1 200 OK transfer-encoding: chunked Content-Type: text/event-stream 5 data: 4 FOO 1 4 java 5 data: 5 JAVA 1 Request Body Response Body
  • 85. Spring WebFlux controller (Receiving Flux) 48 @PostMapping("upper") public Flux<String> upper(@RequestBody Flux<String> input) { Flux<String> output = input .map(String::toUpperCase) .flatMap(s -> Flux .interval(Duration.ofSeconds(1)) .map(i -> s + i) .take(3)); return output; }
  • 86. 49 3 foo HTTP/1.1 200 OK transfer-encoding: chunked Content-Type: text/event-stream 5 data: 5 FOO0 1 5 data: 5 FOO1 1 5 data: 5 FOO2 1
  • 87. DEMO
  • 88. Spring MVC controller (Receiving Flux) 51 @RestController public class HelloController { @PostMapping("upper") public Flux<String> hello(@RequestBody Flux<String> input) { Flux<String> output = input .map(String::toUpperCase); return output; } }
  • 89. Spring MVC controller (Receiving Flux) 51 @RestController public class HelloController { @PostMapping("upper") public Flux<String> hello(@RequestBody Flux<String> input) { Flux<String> output = input .map(String::toUpperCase); return output; } } 🙅
  • 90. Spring MVC controller (Receiving Flux) 51 @RestController public class HelloController { @PostMapping("upper") public Flux<String> hello(@RequestBody Flux<String> input) { Flux<String> output = input .map(String::toUpperCase); return output; } } 🙅Reactive type are supported only as controller method return values
  • 91. Broadcast stream 52 @RestController public class HelloController { private final Flux<String> flux; public HelloController() { this.flux = this.createHotStream().share(); this.flux.subscribe(); } @GetMapping("hello") public Flux<String> hello() { return this.flux; }}
  • 92. Broadcast stream 52 @RestController public class HelloController { private final Flux<String> flux; public HelloController() { this.flux = this.createHotStream().share(); this.flux.subscribe(); } @GetMapping("hello") public Flux<String> hello() { return this.flux; }} this stream is shared by all http clients!
  • 96. Web Stacks in Spring 5 55 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet Stack
  • 97. Web Stacks in Spring 5 55 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet Stack •Annotated Controller •Function Endpoints (WebFlux.fn)
  • 98. @Configuration public class RouterConfig { @Bean public RouterFunctions<ServerResponse> routes() { return route(GET("hello"), req -> { return ServerReponse.ok() .body(Mono.just("hello"), String.class); }); } } Spring WebFlux.fn 56
  • 99. @Configuration public class RouterConfig { @Bean public RouterFunctions<ServerResponse> routes() { return route(GET("hello"), req -> { return ServerReponse.ok() .body(Mono.just("hello"), String.class); }); } } lambda Spring WebFlux.fn 56
  • 100. Spring WebFlux.fn 57 @Configuration public class RouterConfig { @Bean public RouterFunctions<ServerResponse> routes(HelloHandler helloHandler) { return route(GET("hello"), helloHandler::hello); } }
  • 101. Spring WebFlux.fn 58 public RouterFunctions<ServerResponse> routes(PersonHandeler ph) { return route(GET("person"), ph::findAll) .andRoute(POST("person"), ph::create) .andRoute(GET("person/{id}"), ph::findOne) .andRoute(PUT("person/{id}"), ph::update) .andRoute(DELETE("person/{id}"), ph::delete)); }
  • 102. Spring WebFlux.fn 59 public RouterFunctions<ServerResponse> routes(PersonHandeler ph) { return nest(path("person"), route(GET("/"), ph::findAll) .andRoute(POST("/"), ph::create) .andRoute(GET("/{id}"), ph::findOne) .andRoute(PUT("/{id}"), ph::update) .andRoute(DELETE("/{id}"), ph::delete))); }
  • 103. Web Stacks in Spring 5 60 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet Stack
  • 104. Web Stacks in Spring 5 60 Servlet Container Servlet API Spring MVC Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Servlet Stack Reactive Web Client
  • 105. Reactive Web Client 61 @RestController public class HelloController { private final WebClient client; public HelloController(WebClinet.Builer b) { this.client = b.build(); } @GetMapping("hello") public Flux<String> hello() { return this.client.get().uri("http://blahblah") .retrieve().bodyToFlux(String.class); }}
  • 106. Reactive Web Client 62 Flux<User> users = webClient.get() .uri("http://user-service") .exchange() // => Mono<ClientResponse> .flatMap(r -> r.bodyToFlux(User.class)); // short-cut Flux<User> users = webClient.get() .uri("http://user-service") .retrieve() .bodyToFlux(User.class);
  • 107. Reactive Web Client 63 Mono<User> user = webClient.get() .uri("http://user-service/{id}", id) .header("X-Foo", "foo") .retrieve().bodyToMono(User.class); Mono<User> user = ... Mono<Void> created = webClient.post() .uri("http://user-service") .body(user, User.class) .retrieve().bodyToMono(Void.class);
  • 108. From RestTemplate to WebClient 64 @Controller public class UserController { @GetMapping("users") public String hello(Model model) { List<User> users = restTemplate .getForObject("/users", List.class); model.addAttribute("users", users); return "users"; } }
  • 109. From RestTemplate to WebClient 65 @Controller public class UserController { @GetMapping("users") public String hello(Model model) { Flux<User> users = client.get().uri("/users") .retrieve().bodyToFlux(String.class); model.addAttribute("users", users); return "users"; } }
  • 110. 66 <html> <body> <ul> <li data-th-each="user : ${user}">[[${user}]]</li> </ul> </body> </html>
  • 111. 66 <html> <body> <ul> <li data-th-each="user : ${user}">[[${user}]]</li> </ul> </body> </html> 😀 Spring WebFlux
  • 112. 66 <html> <body> <ul> <li data-th-each="user : ${user}">[[${user}]]</li> </ul> </body> </html> 😀 Spring WebFlux 😨 Spring MVC
  • 113. From RestTemplate to WebClient (Spring MVC) 67 @Controller public class UserController { @GetMapping("users") public Mono<String> hello(Model model) { Flux<User> users = client.get().uri("/users") .retrieve().bodyToFlux(String.class); users.collectList().map(x -> { model.addAttribute("users", x); return "users"; }); }
  • 114. From RestTemplate to WebClient (Spring MVC) 67 @Controller public class UserController { @GetMapping("users") public Mono<String> hello(Model model) { Flux<User> users = client.get().uri("/users") .retrieve().bodyToFlux(String.class); users.collectList().map(x -> { model.addAttribute("users", x); return "users"; }); } 😀 Spring MVC
  • 115. From RestTemplate to WebClient (Spring MVC) 68 @Controller public class UserController { @GetMapping("users") public Mono<String> hello(Model model) { Flux<User> users = ...; Mono<Sting> foo = ...; return Mono.zip(user.collectList(), foo)    .map(tpl -> { model.addAttribute("users", tpl.getT1()); model.addAttribute("foo", tpl.getT2()); return "users"; });}}
  • 116. 69 String url = "http://httpbin.org/delay/1"; @GetMapping("hello") public Mono<String> hello() { Mono<String> mono = Mono.just(restTemplate .getForObject(url)); return mono; }
  • 117. ⚠ Don't block the thread in WebFlux! 69 String url = "http://httpbin.org/delay/1"; @GetMapping("hello") public Mono<String> hello() { Mono<String> mono = Mono.just(restTemplate .getForObject(url)); return mono; }
  • 118. ⚠ Don't block the thread in WebFlux! 69 String url = "http://httpbin.org/delay/1"; @GetMapping("hello") public Mono<String> hello() { Mono<String> mono = Mono.just(restTemplate .getForObject(url)); return mono; } 😠 Blocking!
  • 119. ⚠ Don't block the thread in WebFlux! 70 String url = "http://httpbin.org/delay/1"; @GetMapping("hello") public Mono<String> hello() { Mono<String> mono = Mono .fromCallable(() ->restTemplate.getForObject(url)) .subscribeOn(Schedulers.elastic()); return mono; }
  • 120. ⚠ Don't block the thread in WebFlux! 70 String url = "http://httpbin.org/delay/1"; @GetMapping("hello") public Mono<String> hello() { Mono<String> mono = Mono .fromCallable(() ->restTemplate.getForObject(url)) .subscribeOn(Schedulers.elastic()); return mono; } Switch the execution context
  • 121. 71 Concurrency Throughput [trans / sec] Core i7 2.7 GHz 4 Core x HT
  • 122. Reactive Support in Spring Projects 72 Spring Data Reactive Stack Netty, Servlet 3.1+, Undertow Reactive Streams Spring WebFlux Spring Security Thymeleaf
  • 123. Spring Data Kay 73 Reactive support for • Redis • MongoDB • Couchbase • Cassandra Infinite streams from the database with @Tailable
  • 124. Reactive Non-Blocking Data Access 74 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) // ... }
  • 125. Tailable Cursor Support for MongoDB 75 public interface MessageRepository extends ReactiveMongoRepository<Message,String> { @Tailable Flux<Message> findByUpdatedAtGreaterThan(Instant target); }
  • 126. Broadcast updated messages in MongoDB 76 @RestController public class HelloController { private final Flux<Message> messages; public HelloController(MessageRepository repo) { this.messages = repo .findByUpdatedAtGreaterThan(Instant.now()) .share(); this.messages.subscribe(); } @GetMapping("messages") public Flux<Message> messages() { return this.messages; }}
  • 127. But, but, JDBC is blocking .... 😭 77
  • 128. But, but, JDBC is blocking .... 😭 77 Let's see what will happen in next Java
  • 129. But, but, JDBC is blocking .... 😭 77 Let's see what will happen in next Java https://static.rainfocus.com/oracle/oow17/sess/1491948952321001dm4m/PF/JavaOne%2017%20- %20CON1491_1506954898905001IipH.pdf
  • 132. Spring Security Reactive 79 @Bean public SecurityWebFilterChain springWebFilterChain(HttpSecurity http) { return http.authorizeExchange() .pathMatchers("/v2/**").hasRole("ADMIN") .and().httpBasic().and().build(); } @Bean public MapUserDetailsRepository userDetailsRepository() { return new MapUserDetailsRepository(...); }
  • 133. Thymeleaf 3.0 reactive support 80 • "full mode" • "chunked mode"
 => Progressive rendering. Good for large pages • "data-driven mode" 
 => Rendering template fragments as Server-Sent Events
 • https://github.com/thymeleaf/thymeleaf-spring/issues/132 • https://github.com/spring-projects/spring-boot/issues/8124 • https://speakerdeck.com/dfernandez/o-2017-getting-thymeleaf-ready- for-spring-5-and-reactive?slide=18 transfer-encoding: chunked
  • 134. Data-driven mode 81 @GetMapping("users") public String hello(Model model) { Flux<User> users = userService.findAll(); ReactiveDataDriverContextVariable v = new ReactiveDataDriverContextVariable(users, 1); model.addAttribute("users", v); return "users"; }
  • 135. DEMO
  • 136. Reactive Application Patterns (as of 2017) 83
  • 137. Reactive Application Patterns (as of 2017) 83 Spring WebFluxSpring WebFlux Frontend Backend HTTP NoSQL WebClient Spring Data
  • 138. Reactive Application Patterns (as of 2017) 84 Spring MVCSpring WebFlux Frontend Backend HTTP RDB JDBC WebClient
  • 139. Reactive Application Patterns (as of 2017) 85 Spring MVCSpring MVC Frontend Backend HTTP RDB JDBC WebClient
  • 140. Spring Cloud Gateway 86 A Gateway built on Spring Framework 5.0 and Spring Boot 2.0 providing routing and more http://cloud.spring.io/spring-cloud-gateway/ http://cloud.spring.io/spring-cloud-gateway/2.0.x/single/ spring-cloud-gateway.html
  • 141. Start Spring 5 & Spring Boot 2 87
  • 142. Servlet Stack ⇄ Reactive Stack 88 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> Reactive Stack Servlet Stack
  • 143. Servlet Stack ⇄ Reactive Stack 89 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webflux</artifactId> </dependency> <dependency> <groupId>io.projectreactor.ipc</groupId> <artifactId>reactor-netty</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> Reactive Stack Servlet Stack + WebClient
  • 144. Thanks! 90 Resources • Servlet vs Reactive Stacks in Five Use Cases • Spring Boot 2 0 Web Applications • Spring Framework 5: Themes & Trends • Why Spring ❤ Kotlin