SlideShare a Scribd company logo
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

More Related Content

What's hot

Understanding Reactive Programming
Understanding Reactive ProgrammingUnderstanding Reactive Programming
Understanding Reactive Programming
Andres Almiray
 
Introduction to Spring webflux
Introduction to Spring webfluxIntroduction to Spring webflux
Introduction to Spring webflux
Knoldus Inc.
 
React
React React
React
중운 박
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
Dzmitry Naskou
 
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Scrum Breakfast Vietnam
 
Declarative Concurrency with Reactive Programming
Declarative Concurrency with Reactive ProgrammingDeclarative Concurrency with Reactive Programming
Declarative Concurrency with Reactive Programming
Florian Stefan
 
Spring AOP in Nutshell
Spring AOP in Nutshell Spring AOP in Nutshell
Spring AOP in Nutshell
Onkar Deshpande
 
Project Reactor By Example
Project Reactor By ExampleProject Reactor By Example
Project Reactor By Example
Denny Abraham Cheriyan
 
Spring boot
Spring bootSpring boot
Spring boot
sdeeg
 
Hexagonal architecture with Spring Boot
Hexagonal architecture with Spring BootHexagonal architecture with Spring Boot
Hexagonal architecture with Spring Boot
Mikalai Alimenkou
 
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
Richard Langlois P. Eng.
 
Introduction to Reactive programming
Introduction to Reactive programmingIntroduction to Reactive programming
Introduction to Reactive programming
Dwi Randy Herdinanto
 
Benefits of Reactive Programming with Reactor and Spring Boot 2 - Violeta Geo...
Benefits of Reactive Programming with Reactor and Spring Boot 2 - Violeta Geo...Benefits of Reactive Programming with Reactor and Spring Boot 2 - Violeta Geo...
Benefits of Reactive Programming with Reactor and Spring Boot 2 - Violeta Geo...
VMware Tanzu
 
Spring boot
Spring bootSpring boot
Spring boot
Pradeep Shanmugam
 
Introduction to Spring Boot
Introduction to Spring BootIntroduction to Spring Boot
Introduction to Spring Boot
Purbarun Chakrabarti
 
Implementing security requirements for banking API system using Open Source ...
 Implementing security requirements for banking API system using Open Source ... Implementing security requirements for banking API system using Open Source ...
Implementing security requirements for banking API system using Open Source ...
Yuichi Nakamura
 
Reactive Microservices with Spring 5: WebFlux
Reactive Microservices with Spring 5: WebFlux Reactive Microservices with Spring 5: WebFlux
Reactive Microservices with Spring 5: WebFlux
Trayan Iliev
 
Spring Framework - MVC
Spring Framework - MVCSpring Framework - MVC
Spring Framework - MVC
Dzmitry Naskou
 
Spring Boot
Spring BootSpring Boot
Spring Boot
Jiayun Zhou
 

What's hot (20)

Understanding Reactive Programming
Understanding Reactive ProgrammingUnderstanding Reactive Programming
Understanding Reactive Programming
 
Introduction to Spring webflux
Introduction to Spring webfluxIntroduction to Spring webflux
Introduction to Spring webflux
 
React
React React
React
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
 
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
 
Declarative Concurrency with Reactive Programming
Declarative Concurrency with Reactive ProgrammingDeclarative Concurrency with Reactive Programming
Declarative Concurrency with Reactive Programming
 
Spring AOP in Nutshell
Spring AOP in Nutshell Spring AOP in Nutshell
Spring AOP in Nutshell
 
Project Reactor By Example
Project Reactor By ExampleProject Reactor By Example
Project Reactor By Example
 
rx-java-presentation
rx-java-presentationrx-java-presentation
rx-java-presentation
 
Spring boot
Spring bootSpring boot
Spring boot
 
Hexagonal architecture with Spring Boot
Hexagonal architecture with Spring BootHexagonal architecture with Spring Boot
Hexagonal architecture with Spring Boot
 
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 Reactive programming
Introduction to Reactive programmingIntroduction to Reactive programming
Introduction to Reactive programming
 
Benefits of Reactive Programming with Reactor and Spring Boot 2 - Violeta Geo...
Benefits of Reactive Programming with Reactor and Spring Boot 2 - Violeta Geo...Benefits of Reactive Programming with Reactor and Spring Boot 2 - Violeta Geo...
Benefits of Reactive Programming with Reactor and Spring Boot 2 - Violeta Geo...
 
Spring boot
Spring bootSpring boot
Spring boot
 
Introduction to Spring Boot
Introduction to Spring BootIntroduction to Spring Boot
Introduction to Spring Boot
 
Implementing security requirements for banking API system using Open Source ...
 Implementing security requirements for banking API system using Open Source ... Implementing security requirements for banking API system using Open Source ...
Implementing security requirements for banking API system using Open Source ...
 
Reactive Microservices with Spring 5: WebFlux
Reactive Microservices with Spring 5: WebFlux Reactive Microservices with Spring 5: WebFlux
Reactive Microservices with Spring 5: WebFlux
 
Spring Framework - MVC
Spring Framework - MVCSpring Framework - MVC
Spring Framework - MVC
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 

Similar to Introduction to Spring WebFlux #jsug #sf_a1

Arquitecturas de microservicios - Medianet Software
Arquitecturas de microservicios   -  Medianet SoftwareArquitecturas de microservicios   -  Medianet Software
Arquitecturas de microservicios - Medianet Software
Ernesto Hernández Rodríguez
 
FrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftFrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) Swift
Chris 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 & Couchbase
Alex 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 edition
Christian Panadero
 
Hexagonal architecture in PHP
Hexagonal architecture in PHPHexagonal architecture in PHP
Hexagonal architecture in PHP
Paulo Victor Gomes
 
groovy & grails - lecture 13
groovy & grails - lecture 13groovy & grails - lecture 13
groovy & grails - lecture 13
Alexandre Masselot
 
Spring 4 Web App
Spring 4 Web AppSpring 4 Web App
Spring 4 Web App
Rossen Stoyanchev
 
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
Simone Chiaretta
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
Dongmin 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 8
Chaitanya 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 2018
Loiane 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_001
Sven Ruppert
 
Openshift31-tech.ppt
Openshift31-tech.pptOpenshift31-tech.ppt
Openshift31-tech.ppt
AJAYKUMAR836335
 
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
Loiane 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 Girl
Loiane Groner
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + Angular
Loiane 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 JaFu
VMware 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 2020
Matt Raible
 
RxJava Applied
RxJava AppliedRxJava Applied
RxJava Applied
Igor Lozynskyi
 
Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019
Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019
Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019
Loiane Groner
 

Similar to 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
 
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
 
Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019
Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019
Full-Stack Reactive with Spring WebFlux + Angular - JConf Colombia 2019
 

More from 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 #jsug
Toshiaki Maki
 
Concourse x Spinnaker #concourse_tokyo
Concourse x Spinnaker #concourse_tokyoConcourse x Spinnaker #concourse_tokyo
Concourse x Spinnaker #concourse_tokyo
Toshiaki 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 #s1t
Toshiaki Maki
 
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
Toshiaki 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_a1
Toshiaki Maki
 
Spring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerSpring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & Micrometer
Toshiaki 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 #k8sjp
Toshiaki Maki
 
Spring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugSpring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsug
Toshiaki 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_tokyo
Toshiaki 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 Boot
Toshiaki Maki
 
Zipkin Components #zipkin_jp
Zipkin Components #zipkin_jpZipkin Components #zipkin_jp
Zipkin Components #zipkin_jp
Toshiaki Maki
 
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
Toshiaki 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 #JavaDayTokyo
Toshiaki Maki
 
実例で学ぶ、明日から使えるSpring Boot Tips #jsug
実例で学ぶ、明日から使えるSpring Boot Tips #jsug実例で学ぶ、明日から使えるSpring Boot Tips #jsug
実例で学ぶ、明日から使えるSpring Boot Tips #jsug
Toshiaki Maki
 
Spring ❤️ Kotlin #jjug
Spring ❤️ Kotlin #jjugSpring ❤️ Kotlin #jjug
Spring ❤️ Kotlin #jjug
Toshiaki 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_ab3
Toshiaki 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 CI
Toshiaki 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 #cfdtokyo
Toshiaki Maki
 
今すぐ始めるCloud Foundry #hackt #hackt_k
今すぐ始めるCloud Foundry #hackt #hackt_k今すぐ始めるCloud Foundry #hackt #hackt_k
今すぐ始めるCloud Foundry #hackt #hackt_k
Toshiaki Maki
 

More from 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
 

Recently uploaded

Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 

Recently uploaded (20)

Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 

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