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

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

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

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

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

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

=> Rendering template fragments as Server-Sent Events

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

More Related Content

What's hot

Comparing Native Java REST API Frameworks - Seattle JUG 2022
Comparing Native Java REST API Frameworks - Seattle JUG 2022Comparing Native Java REST API Frameworks - Seattle JUG 2022
Comparing Native Java REST API Frameworks - Seattle JUG 2022
Matt Raible
 
Reactive programming intro
Reactive programming introReactive programming intro
Reactive programming intro
Ahmed Ehab AbdulAziz
 
Project Reactor Now and Tomorrow
Project Reactor Now and TomorrowProject Reactor Now and Tomorrow
Project Reactor Now and Tomorrow
VMware Tanzu
 
Squirreling Away $640 Billion: How Stripe Leverages Flink for Change Data Cap...
Squirreling Away $640 Billion: How Stripe Leverages Flink for Change Data Cap...Squirreling Away $640 Billion: How Stripe Leverages Flink for Change Data Cap...
Squirreling Away $640 Billion: How Stripe Leverages Flink for Change Data Cap...
Flink Forward
 
Reactive Programming In Java Using: Project Reactor
Reactive Programming In Java Using: Project ReactorReactive Programming In Java Using: Project Reactor
Reactive Programming In Java Using: Project Reactor
Knoldus Inc.
 
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Scrum Breakfast Vietnam
 
What's the time? ...and why? (Mattias Sax, Confluent) Kafka Summit SF 2019
What's the time? ...and why? (Mattias Sax, Confluent) Kafka Summit SF 2019What's the time? ...and why? (Mattias Sax, Confluent) Kafka Summit SF 2019
What's the time? ...and why? (Mattias Sax, Confluent) Kafka Summit SF 2019
confluent
 
Introducing the Apache Flink Kubernetes Operator
Introducing the Apache Flink Kubernetes OperatorIntroducing the Apache Flink Kubernetes Operator
Introducing the Apache Flink Kubernetes Operator
Flink Forward
 
Exactly-Once Financial Data Processing at Scale with Flink and Pinot
Exactly-Once Financial Data Processing at Scale with Flink and PinotExactly-Once Financial Data Processing at Scale with Flink and Pinot
Exactly-Once Financial Data Processing at Scale with Flink and Pinot
Flink Forward
 
[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring
Knoldus Inc.
 
Apache Kafka Best Practices
Apache Kafka Best PracticesApache Kafka Best Practices
Apache Kafka Best Practices
DataWorks Summit/Hadoop Summit
 
Tuning Apache Kafka Connectors for Flink.pptx
Tuning Apache Kafka Connectors for Flink.pptxTuning Apache Kafka Connectors for Flink.pptx
Tuning Apache Kafka Connectors for Flink.pptx
Flink Forward
 
Building a fully managed stream processing platform on Flink at scale for Lin...
Building a fully managed stream processing platform on Flink at scale for Lin...Building a fully managed stream processing platform on Flink at scale for Lin...
Building a fully managed stream processing platform on Flink at scale for Lin...
Flink Forward
 
Redis at LINE
Redis at LINERedis at LINE
Redis at LINE
LINE Corporation
 
Reactive Programming
Reactive ProgrammingReactive Programming
Reactive Programming
Knoldus Inc.
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
Joshua Long
 
Reactive Microservices with Spring 5: WebFlux
Reactive Microservices with Spring 5: WebFlux Reactive Microservices with Spring 5: WebFlux
Reactive Microservices with Spring 5: WebFlux
Trayan Iliev
 
Kafka 101 and Developer Best Practices
Kafka 101 and Developer Best PracticesKafka 101 and Developer Best Practices
Kafka 101 and Developer Best Practices
confluent
 
Microservices with Spring 5 Webflux - jProfessionals
Microservices  with Spring 5 Webflux - jProfessionalsMicroservices  with Spring 5 Webflux - jProfessionals
Microservices with Spring 5 Webflux - jProfessionals
Trayan Iliev
 
Spring Framework - Data Access
Spring Framework - Data AccessSpring Framework - Data Access
Spring Framework - Data Access
Dzmitry Naskou
 

What's hot (20)

Comparing Native Java REST API Frameworks - Seattle JUG 2022
Comparing Native Java REST API Frameworks - Seattle JUG 2022Comparing Native Java REST API Frameworks - Seattle JUG 2022
Comparing Native Java REST API Frameworks - Seattle JUG 2022
 
Reactive programming intro
Reactive programming introReactive programming intro
Reactive programming intro
 
Project Reactor Now and Tomorrow
Project Reactor Now and TomorrowProject Reactor Now and Tomorrow
Project Reactor Now and Tomorrow
 
Squirreling Away $640 Billion: How Stripe Leverages Flink for Change Data Cap...
Squirreling Away $640 Billion: How Stripe Leverages Flink for Change Data Cap...Squirreling Away $640 Billion: How Stripe Leverages Flink for Change Data Cap...
Squirreling Away $640 Billion: How Stripe Leverages Flink for Change Data Cap...
 
Reactive Programming In Java Using: Project Reactor
Reactive Programming In Java Using: Project ReactorReactive Programming In Java Using: Project Reactor
Reactive Programming In Java Using: Project Reactor
 
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
Reactive programming by spring webflux - DN Scrum Breakfast - Nov 2018
 
What's the time? ...and why? (Mattias Sax, Confluent) Kafka Summit SF 2019
What's the time? ...and why? (Mattias Sax, Confluent) Kafka Summit SF 2019What's the time? ...and why? (Mattias Sax, Confluent) Kafka Summit SF 2019
What's the time? ...and why? (Mattias Sax, Confluent) Kafka Summit SF 2019
 
Introducing the Apache Flink Kubernetes Operator
Introducing the Apache Flink Kubernetes OperatorIntroducing the Apache Flink Kubernetes Operator
Introducing the Apache Flink Kubernetes Operator
 
Exactly-Once Financial Data Processing at Scale with Flink and Pinot
Exactly-Once Financial Data Processing at Scale with Flink and PinotExactly-Once Financial Data Processing at Scale with Flink and Pinot
Exactly-Once Financial Data Processing at Scale with Flink and Pinot
 
[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring[Webinar]: Working with Reactive Spring
[Webinar]: Working with Reactive Spring
 
Apache Kafka Best Practices
Apache Kafka Best PracticesApache Kafka Best Practices
Apache Kafka Best Practices
 
Tuning Apache Kafka Connectors for Flink.pptx
Tuning Apache Kafka Connectors for Flink.pptxTuning Apache Kafka Connectors for Flink.pptx
Tuning Apache Kafka Connectors for Flink.pptx
 
Building a fully managed stream processing platform on Flink at scale for Lin...
Building a fully managed stream processing platform on Flink at scale for Lin...Building a fully managed stream processing platform on Flink at scale for Lin...
Building a fully managed stream processing platform on Flink at scale for Lin...
 
Redis at LINE
Redis at LINERedis at LINE
Redis at LINE
 
Reactive Programming
Reactive ProgrammingReactive Programming
Reactive Programming
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
Reactive Microservices with Spring 5: WebFlux
Reactive Microservices with Spring 5: WebFlux Reactive Microservices with Spring 5: WebFlux
Reactive Microservices with Spring 5: WebFlux
 
Kafka 101 and Developer Best Practices
Kafka 101 and Developer Best PracticesKafka 101 and Developer Best Practices
Kafka 101 and Developer Best Practices
 
Microservices with Spring 5 Webflux - jProfessionals
Microservices  with Spring 5 Webflux - jProfessionalsMicroservices  with Spring 5 Webflux - jProfessionals
Microservices with Spring 5 Webflux - jProfessionals
 
Spring Framework - Data Access
Spring Framework - Data AccessSpring Framework - Data Access
Spring Framework - Data Access
 

Similar to Introduction to Spring WebFlux #jsug #sf_a1

Arquitecturas de microservicios - Medianet Software
Arquitecturas de microservicios   -  Medianet SoftwareArquitecturas de microservicios   -  Medianet Software
Arquitecturas de microservicios - Medianet Software
Ernesto Hernández Rodríguez
 
FrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftFrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) Swift
Chris Bailey
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & Couchbase
Alex Derkach
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca edition
Christian Panadero
 
Hexagonal architecture in PHP
Hexagonal architecture in PHPHexagonal architecture in PHP
Hexagonal architecture in PHP
Paulo Victor Gomes
 
groovy & grails - lecture 13
groovy & grails - lecture 13groovy & grails - lecture 13
groovy & grails - lecture 13
Alexandre Masselot
 
Spring 4 Web App
Spring 4 Web AppSpring 4 Web App
Spring 4 Web App
Rossen Stoyanchev
 
Ruby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVCRuby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVC
Simone Chiaretta
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
Dongmin Yu
 
SoCal Code Camp 2015: An introduction to Java 8
SoCal Code Camp 2015: An introduction to Java 8SoCal Code Camp 2015: An introduction to Java 8
SoCal Code Camp 2015: An introduction to Java 8
Chaitanya Ganoo
 
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
Full-Stack Reactive with Spring WebFlux + Angular - Oracle Code One 2018
Loiane Groner
 
Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001Proxy deep-dive java-one_20151027_001
Proxy deep-dive java-one_20151027_001
Sven Ruppert
 
Openshift31-tech.ppt
Openshift31-tech.pptOpenshift31-tech.ppt
Openshift31-tech.ppt
AJAYKUMAR836335
 
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConfFull-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Loiane Groner
 
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java GirlFull-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Full-Stack Reativo com Spring WebFlux + Angular - Devs Java Girl
Loiane Groner
 
Spring Boot
Spring BootSpring Boot
Spring Boot
Jiayun Zhou
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + Angular
Loiane Groner
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFu
VMware Tanzu
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
Matt Raible
 
RxJava Applied
RxJava AppliedRxJava Applied
RxJava Applied
Igor Lozynskyi
 

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
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + Angular
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFu
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
 
RxJava Applied
RxJava AppliedRxJava Applied
RxJava Applied
 

More from Toshiaki Maki

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

More from Toshiaki Maki (20)

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

Recently uploaded

UI5 Controls simplified - UI5con2024 presentation
UI5 Controls simplified - UI5con2024 presentationUI5 Controls simplified - UI5con2024 presentation
UI5 Controls simplified - UI5con2024 presentation
Wouter Lemaire
 
Serial Arm Control in Real Time Presentation
Serial Arm Control in Real Time PresentationSerial Arm Control in Real Time Presentation
Serial Arm Control in Real Time Presentation
tolgahangng
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Malak Abu Hammad
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
MichaelKnudsen27
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
panagenda
 
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Jeffrey Haguewood
 
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdfHow to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
Chart Kalyan
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
Zilliz
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
Matthew Sinclair
 
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
Edge AI and Vision Alliance
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
saastr
 
Recommendation System using RAG Architecture
Recommendation System using RAG ArchitectureRecommendation System using RAG Architecture
Recommendation System using RAG Architecture
fredae14
 
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial IntelligenceAI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
IndexBug
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Tosin Akinosho
 
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Speck&Tech
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
Pixlogix Infotech
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
Hiroshi SHIBATA
 
GenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizationsGenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizations
kumardaparthi1024
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Alpen-Adria-Universität
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
Jason Packer
 

Recently uploaded (20)

UI5 Controls simplified - UI5con2024 presentation
UI5 Controls simplified - UI5con2024 presentationUI5 Controls simplified - UI5con2024 presentation
UI5 Controls simplified - UI5con2024 presentation
 
Serial Arm Control in Real Time Presentation
Serial Arm Control in Real Time PresentationSerial Arm Control in Real Time Presentation
Serial Arm Control in Real Time Presentation
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
 
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
 
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdfHow to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
 
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
“Building and Scaling AI Applications with the Nx AI Manager,” a Presentation...
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
 
Recommendation System using RAG Architecture
Recommendation System using RAG ArchitectureRecommendation System using RAG Architecture
Recommendation System using RAG Architecture
 
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial IntelligenceAI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
 
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
 
GenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizationsGenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizations
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
 

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