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

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

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

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

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

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

=> Rendering template fragments as Server-Sent Events

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

More Related Content

What's hot

Reactive Card Magic: Understanding Spring WebFlux and Project Reactor
Reactive Card Magic: Understanding Spring WebFlux and Project ReactorReactive Card Magic: Understanding Spring WebFlux and Project Reactor
Reactive Card Magic: Understanding Spring WebFlux and Project ReactorVMware Tanzu
 
[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive SpringKnoldus Inc.
 
Introduction to Spring webflux
Introduction to Spring webfluxIntroduction to Spring webflux
Introduction to Spring webfluxKnoldus Inc.
 
Microservices with Java, Spring Boot and Spring Cloud
Microservices with Java, Spring Boot and Spring CloudMicroservices with Java, Spring Boot and Spring Cloud
Microservices with Java, Spring Boot and Spring CloudEberhard Wolff
 
Spring Native and Spring AOT
Spring Native and Spring AOTSpring Native and Spring AOT
Spring Native and Spring AOTVMware Tanzu
 
How to Avoid Common Mistakes When Using Reactor Netty
How to Avoid Common Mistakes When Using Reactor NettyHow to Avoid Common Mistakes When Using Reactor Netty
How to Avoid Common Mistakes When Using Reactor NettyVMware Tanzu
 
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...GreeceJS
 
Servlet vs Reactive Stacks in 5 Use Cases
Servlet vs Reactive Stacks in 5 Use CasesServlet vs Reactive Stacks in 5 Use Cases
Servlet vs Reactive Stacks in 5 Use CasesVMware Tanzu
 
Declarative Concurrency with Reactive Programming
Declarative Concurrency with Reactive ProgrammingDeclarative Concurrency with Reactive Programming
Declarative Concurrency with Reactive ProgrammingFlorian Stefan
 
Reactive Programming for Real Use Cases
Reactive Programming for Real Use CasesReactive Programming for Real Use Cases
Reactive Programming for Real Use CasesAlex Soto
 
Kafka Retry and DLQ
Kafka Retry and DLQKafka Retry and DLQ
Kafka Retry and DLQGeorge Teo
 
Spring Framework - Core
Spring Framework - CoreSpring Framework - Core
Spring Framework - CoreDzmitry Naskou
 
Networking in Java with NIO and Netty
Networking in Java with NIO and NettyNetworking in Java with NIO and Netty
Networking in Java with NIO and NettyConstantine Slisenka
 
Best Practices for Middleware and Integration Architecture Modernization with...
Best Practices for Middleware and Integration Architecture Modernization with...Best Practices for Middleware and Integration Architecture Modernization with...
Best Practices for Middleware and Integration Architecture Modernization with...Claus Ibsen
 
Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理土岐 孝平
 
Microservice vs. Monolithic Architecture
Microservice vs. Monolithic ArchitectureMicroservice vs. Monolithic Architecture
Microservice vs. Monolithic ArchitecturePaul Mooney
 

What's hot (20)

Reactive Card Magic: Understanding Spring WebFlux and Project Reactor
Reactive Card Magic: Understanding Spring WebFlux and Project ReactorReactive Card Magic: Understanding Spring WebFlux and Project Reactor
Reactive Card Magic: Understanding Spring WebFlux and Project Reactor
 
[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring
 
Introduction to Spring webflux
Introduction to Spring webfluxIntroduction to Spring webflux
Introduction to Spring webflux
 
Microservices with Java, Spring Boot and Spring Cloud
Microservices with Java, Spring Boot and Spring CloudMicroservices with Java, Spring Boot and Spring Cloud
Microservices with Java, Spring Boot and Spring Cloud
 
Springboot Microservices
Springboot MicroservicesSpringboot Microservices
Springboot Microservices
 
Spring Native and Spring AOT
Spring Native and Spring AOTSpring Native and Spring AOT
Spring Native and Spring AOT
 
How to Avoid Common Mistakes When Using Reactor Netty
How to Avoid Common Mistakes When Using Reactor NettyHow to Avoid Common Mistakes When Using Reactor Netty
How to Avoid Common Mistakes When Using Reactor Netty
 
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
 
Introduction to Spring Boot
Introduction to Spring BootIntroduction to Spring Boot
Introduction to Spring Boot
 
Servlet vs Reactive Stacks in 5 Use Cases
Servlet vs Reactive Stacks in 5 Use CasesServlet vs Reactive Stacks in 5 Use Cases
Servlet vs Reactive Stacks in 5 Use Cases
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Project Reactor By Example
Project Reactor By ExampleProject Reactor By Example
Project Reactor By Example
 
Declarative Concurrency with Reactive Programming
Declarative Concurrency with Reactive ProgrammingDeclarative Concurrency with Reactive Programming
Declarative Concurrency with Reactive Programming
 
Reactive Programming for Real Use Cases
Reactive Programming for Real Use CasesReactive Programming for Real Use Cases
Reactive Programming for Real Use Cases
 
Kafka Retry and DLQ
Kafka Retry and DLQKafka Retry and DLQ
Kafka Retry and DLQ
 
Spring Framework - Core
Spring Framework - CoreSpring Framework - Core
Spring Framework - Core
 
Networking in Java with NIO and Netty
Networking in Java with NIO and NettyNetworking in Java with NIO and Netty
Networking in Java with NIO and Netty
 
Best Practices for Middleware and Integration Architecture Modernization with...
Best Practices for Middleware and Integration Architecture Modernization with...Best Practices for Middleware and Integration Architecture Modernization with...
Best Practices for Middleware and Integration Architecture Modernization with...
 
Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理
 
Microservice vs. Monolithic Architecture
Microservice vs. Monolithic ArchitectureMicroservice vs. Monolithic Architecture
Microservice vs. Monolithic Architecture
 

Similar to Introduction to Spring WebFlux #jsug #sf_a1

FrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftFrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftChris Bailey
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseAlex Derkach
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionChristian Panadero
 
Ruby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVCRuby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVCSimone Chiaretta
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomyDongmin Yu
 
SoCal Code Camp 2015: An introduction to Java 8
SoCal Code Camp 2015: An introduction to Java 8SoCal Code Camp 2015: An introduction to Java 8
SoCal Code Camp 2015: An introduction to Java 8Chaitanya Ganoo
 
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018Loiane Groner
 
Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001Sven Ruppert
 
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConfFull-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConfLoiane Groner
 
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java GirlFull-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java GirlLoiane Groner
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularLoiane Groner
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuVMware Tanzu
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020Matt Raible
 
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 2019Loiane 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 #jsugToshiaki Maki
 
Concourse x Spinnaker #concourse_tokyo
Concourse x Spinnaker #concourse_tokyoConcourse x Spinnaker #concourse_tokyo
Concourse x Spinnaker #concourse_tokyoToshiaki Maki
 
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1t
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1tServerless with Spring Cloud Function, Knative and riff #SpringOneTour #s1t
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1tToshiaki Maki
 
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1Toshiaki Maki
 
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1Toshiaki Maki
 
Spring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerSpring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerToshiaki Maki
 
Open Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjpOpen Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjpToshiaki Maki
 
Spring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugSpring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugToshiaki Maki
 
BOSH / CF Deployment in modern ways #cf_tokyo
BOSH / CF Deployment in modern ways #cf_tokyoBOSH / CF Deployment in modern ways #cf_tokyo
BOSH / CF Deployment in modern ways #cf_tokyoToshiaki Maki
 
Why PCF is the best platform for Spring Boot
Why PCF is the best platform for Spring BootWhy PCF is the best platform for Spring Boot
Why PCF is the best platform for Spring BootToshiaki Maki
 
Zipkin Components #zipkin_jp
Zipkin Components #zipkin_jpZipkin Components #zipkin_jp
Zipkin Components #zipkin_jpToshiaki Maki
 
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07Toshiaki Maki
 
Spring Framework 5.0による Reactive Web Application #JavaDayTokyo
Spring Framework 5.0による Reactive Web Application #JavaDayTokyoSpring Framework 5.0による Reactive Web Application #JavaDayTokyo
Spring Framework 5.0による Reactive Web Application #JavaDayTokyoToshiaki Maki
 
実例で学ぶ、明日から使えるSpring Boot Tips #jsug
実例で学ぶ、明日から使えるSpring Boot Tips #jsug実例で学ぶ、明日から使えるSpring Boot Tips #jsug
実例で学ぶ、明日から使えるSpring Boot Tips #jsugToshiaki Maki
 
Spring ❤️ Kotlin #jjug
Spring ❤️ Kotlin #jjugSpring ❤️ Kotlin #jjug
Spring ❤️ Kotlin #jjugToshiaki Maki
 
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3Toshiaki Maki
 
Managing your Docker image continuously with Concourse CI
Managing your Docker image continuously with Concourse CIManaging your Docker image continuously with Concourse CI
Managing your Docker image continuously with Concourse CIToshiaki Maki
 
Data Microservices with Spring Cloud Stream, Task, and Data Flow #jsug #spri...
Data Microservices with Spring Cloud Stream, Task,  and Data Flow #jsug #spri...Data Microservices with Spring Cloud Stream, Task,  and Data Flow #jsug #spri...
Data Microservices with Spring Cloud Stream, Task, and Data Flow #jsug #spri...Toshiaki Maki
 
Short Lived Tasks in Cloud Foundry #cfdtokyo
Short Lived Tasks in Cloud Foundry #cfdtokyoShort Lived Tasks in Cloud Foundry #cfdtokyo
Short Lived Tasks in Cloud Foundry #cfdtokyoToshiaki Maki
 
今すぐ始めるCloud Foundry #hackt #hackt_k
今すぐ始めるCloud Foundry #hackt #hackt_k今すぐ始めるCloud Foundry #hackt #hackt_k
今すぐ始めるCloud Foundry #hackt #hackt_kToshiaki Maki
 

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

DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 

Recently uploaded (20)

DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 

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