christoph strobl pivotal software inc....unless otherwise indicated, these slides are © 2013-2017...
TRANSCRIPT
Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Going with .
Christoph Strobl Pivotal Software Inc.
@stroblchristoph
Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
In a nutshell, reactive programming is about non-blocking, event-driven applications
that scale with a small number of threadswith back pressure as a key ingredient
that aims to ensure producers to not overwhelm consumers.(Rossen Stoyanchev)
The next 60 Minutes
3 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
- A bit of recent history.
- Project Reactor / Spring Data Kay / Spring Framework 5.
- Some Code.
A bit of recent history.
Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Sept 28
5.0 GA
Dec 2017
Oct 2017
Kay GA 2.0 GA
Sept 25
3.1 GA
Sept 29
5.0 M1
Jul 2016
Kay M1
Sept 2016
Nov 2016
3.0 GA
Sept 2015 Sept 21
9
Imperative Applications
5 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
{…}
Imperative Applications - Batching
6 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
{…}Batching
Imperative Applications - Async
7 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
{…}
Dispatcher
Thread: Worker A
Thread: Worker B
Thread: Worker C
Reactive Applications
8 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
{…}Subscriber PublisherStream
Reactive Applications
9 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
{…}Subscriber PublisherStream
.block()
NoSQL for the win!
10 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
11 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Iterator.next() Future.get()
Subscriber.onNext(t)
Remember
vs
Reactor 3.1
Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Reactive Streams
13 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Provider of a potentially unbounded number of sequenced elements.Publisher<T>
Subscriber<T>
A processing stage - actually both a Subscriber and a Publisher.Processor<T,R>
One-to-one lifecycle of a Subscriber subscribing to a Publisher.Subscription
14 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Publisher<T>
Subscriber<T>
Processor<T,R>
Subscription
.subscribe(Subscriber)
.onSubscribe(Subscription)
.request(long)
.onNext(T)
Reactive Streams
Project Reactor
16 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Publisher<T> (0…n)
Flux<T> (0…n) Mono<T> (0…1)
Reactive Streams
Project Reactor
17 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Publisher<T> (0…n)
Flux<T> (0…n) Mono<T> (0…1)
Reactive Streams
Mono<User> findByEmail(String email);
Flux<User> findByName(String name);
#jürgenized
Flux
18 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
[fluhks] - a flowing or flow
Flux.just("red", "white", "blue") .flatMap(v !-> Mono.fromCallable(blockingStuff(v)) .subscribeOn(Schedulers.elastic())) .collect(Result!::new, Result!::add) .doOnNext(Result!::stop) .subscribe(doWithResult);
Mono
19 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
[mon-oh] - alone, single, one
Mono.fromCallable(blockingStuff()) .map(v !-> unwarp(v)) .subscribe();
Reactive Applications with Spring
Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Spring Framework5
Project Reactor3.1
Spring DataKay
Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Apply familiar conceptsto an new way of expressing functionality.
With minimal fluff and surprise!
Reactive Template (MongoDB)
22 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
/** * Query for a {@link Flux} of objects of type T from the specified collection. * * @param entityClass the parametrized type of the returned {@link Flux}. * @param collectionName name of the collection to retrieve the objects from * @return the converted collection */<T> Flux<T> findAll(Class<T> entityClass, String collectionName);
/** * Map the results of an ad-hoc query on the collection for the entity class to a * single instance of an object of the * specified type. * @param query the query class that specifies the criteria * @param entityClass the parametrized type of the returned {@link Mono}. * @return the converted object */<T> Mono<T> findOne(Query query, Class<T> entityClass);
Reactive Repository
23 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
<S extends T> Mono<S> save(S entity);
<S extends T> Mono<S> save(Mono<S> entity); <S extends T> Flux<S> saveAll(Iterable<S> entities);
<S extends T> Flux<S> saveAll(Publisher<S> entities); Mono<Boolean> existsById(Mono<ID> id); Flux<T> findAll(); Mono<Long> count(); Mono<Void> deleteById(ID id);
Spring Data Reactive
24 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
interface Repo extends ReactiveCrudRepository<Person, String> {
}
Flux<Person> findAllByLastname(String lastname); Flux<Person> findAllByLastname(Mono<String> lastname);
Flux<Person> customQuery(String lastname); @Query("{lastname : ?0}");
Flux<Person> findAllByLastname(String ln, Pageable page);
Spring WebFlux
25 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
@RestController static class PersonController { PersonRepository repository; }
@GetMapping("/")Flux<Person> fluxPersons(String name) { return repository.findAllByName(name);}
Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
It’s Demo Time
https://github.com/christophstrobl/going-reactive-with-spring-data
Spring Data - Reactive Repository
27 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
interface PersonRepository extends ReactiveCrudRepository<Person, String> {
}
Flux.interval(Duration.ofSeconds(1)) .zipWith(starks) .map(Tuple2!::getT2) .flatMap(repository!::save) .subscribe();
String[] names = { "Eddard", "Catelyn", "Jon", "Rob", "Sansa", "Aria", "Bran", "Rickon" };
Flux<Person> starks = Flux .fromStream(Stream.generate(() !-> names[ramdom.nextInt(names.length)]) .map(Person!::new));
Spring Data - Reactive Repository
28 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
interface PersonRepository extends ReactiveCrudRepository<Person, String> {
}
Flux.interval(Duration.ofSeconds(1)) .zipWith(starks) .map(Tuple2!::getT2) .flatMap(repository!::save) .subscribe();
String[] names = { "Eddard", "Catelyn", "Jon", "Rob", "Sansa", "Aria", "Bran", "Rickon" };
Flux<Person> starks = Flux .fromStream(Stream.generate(() !-> names[ramdom.nextInt(names.length-1)]) .map(Person!::new));
> cstrobl $ ./bin/mongo --port 52291
> use test switched to db test
{ "_id" : ObjectId("591009c5ed68a820fb9956a5"), "name" : "Sansa", "_class" : "com.example.DemoApplication$Person" } { "_id" : ObjectId("591009c6ed68a820fb9956a6"), "name" : "Rob", "_class" : "com.example.DemoApplication$Person" } { "_id" : ObjectId("591009c7ed68a820fb9956a7"), "name" : "Sansa", "_class" : "com.example.DemoApplication$Person" } { "_id" : ObjectId("591009c8ed68a820fb9956a8"), "name" : "Rob", "_class" : "com.example.DemoApplication$Person" } { "_id" : ObjectId("591009c9ed68a820fb9956a9"), "name" : "Jon", "_class" : "com.example.DemoApplication$Person" } { "_id" : ObjectId("591009caed68a820fb9956aa"), "name" : "Aria", "_class" : "com.example.DemoApplication$Person" } { "_id" : ObjectId("591009cbed68a820fb9956ab"), "name" : "Rob", "_class" : "com.example.DemoApplication$Person" } { "_id" : ObjectId("591009cced68a820fb9956ac"), "name" : "Jon", "_class" : "com.example.DemoApplication$Person" } { "_id" : ObjectId("591009cded68a820fb9956ad"), "name" : "Sansa", "_class" : "com.example.DemoApplication$Person" }
> db.person.find();
Spring - WebFlux
29 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
interface PersonRepository extends ReactiveCrudRepository<Person, String> {
Flux<Person> findAllByName(String name); }
@RestController static class PersonController { PersonRepository repository; }
@GetMapping("/")Flux<Person> fluxPersons(String name) { return repository.findAllByName(name);}
Spring - WebFlux
30 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
interface PersonRepository extends ReactiveCrudRepository<Person, String> {
Flux<Person> findAllByName(String name); }
@RestController static class PersonController { PersonRepository repository; }
@GetMapping("/")Flux<Person> fluxPersons(String name) { return repository.findAllByName(name);}
> cstrobl $ curl localhost:8080/?name=Eddard | jq
[ { "name": "Eddard", "id": "591014f2756bac231a23f3a0" }, { "name": "Eddard", "id": "591014f7756bac231a23f3a5" } ]
>
RxJava types
31 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
interface PersonRepository extends ReactiveCrudRepository<Person, String> {
Observable<Person> findByName(String name); }
@RestController static class PersonController { PersonRepository repository; @GetMapping("/rx") Observable<Person> rxPersons(String name) { return repository.findByName(name); }}
RxJava types
32 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
interface PersonRepository extends ReactiveCrudRepository<Person, String> {
Observable<Person> findByName(String name); }
@RestController static class PersonController { PersonRepository repository; @GetMapping("/rx") Observable<Person> rxPersons(String name) { return repository.findByName(name); }}
> cstrobl $ curl localhost:8080/rx?name=Rob | jq [ { "name": "Rob", "id": "590f6e99756bac18a8d62bfe" }, { "name": "Rob", "id": "590f6e9d756bac18a8d62c02" } { "name": "Rob", "id": "590f6e9e756bac18a8d62c03" } ]
>
Tailable Cursors & Event Stream
33 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
interface PersonRepository extends ReactiveCrudRepository<Person, String> {
@Tailable Flux<Person> findBy(); }
@RestController static class PersonController { PersonRepository repository; @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) Flux<Person> streamPersons() { return repository.findBy(); }}
Tailable Cursors & Event Stream
34 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
interface PersonRepository extends ReactiveCrudRepository<Person, String> {
@Tailable Flux<Person> findBy(); }
@RestController static class PersonController { PersonRepository repository; @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) Flux<Person> streamPersons() { return repository.findBy(); }}
> cstrobl $ curl localhost:8080/stream
data:{"name":"Sansa","id":"5910192e756bac26079dd623"}
data:{"name":"Jon","id":"5910192f756bac26079dd624"}
data:{"name":"Catelyn","id":"59101930756bac26079dd625"}
data:{"name":"Eddard","id":"59101931756bac26079dd626"}
data:{"name":"Jon","id":"59101932756bac26079dd627"}
data:{"name":"Eddard","id":"59101933756bac26079dd628"}
WebFlux - Router Functions
35 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
@Componentstatic class PersonHandler {
PersonRepository repository;
Mono<ServerResponse> streamPersons(ServerRequest request) { return ServerResponse.ok() .contentType(MediaType.TEXT_EVENT_STREAM) .body(personRepository.findBy(), Person.class); }
@BeanRouterFunction<ServerResponse> routes(PersonHandler requestHandler) { return RouterFunctions .route(RequestPredicates.GET("/stream"), requestHandler!::streamPersons) }
Spring - WebClient
36 Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
@BeanWebClient client() { return WebClient.create("http:!//localhost:8080/");}@BeanCommandLineRunner run(WebClient client) { return (args) !-> { client.get() .uri("/stream") .retrieve() .bodyToFlux(Person.class) .subscribe(System.out!::println); };}
Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/
Reactive is about efficient resource usage. Even if backed with familiar concepts and framework support,
it is no free lunch. The price is complexity.