Spring I/O 2017報告会
- Functional Web Framework
- Spring DataのReactive対応
2017/6/29 JSUG勉強会
2017/6/29 JSUG勉強会
Session | Speaker |
---|---|
Reactor 3, the reactive foundation for Java 8 (and Spring 5) | Simon Baslé |
New in Spring 5: Functional Web Framework | Arjen Poutsma |
Reactive Meets Data Access | Christoph Strobl |
槙さん講演@Java Day Tokyo 2017
「Spring Framework 5.0によるReactive Web Application」
の激しい劣化版に結果的になってしまったこと
ご了承ください。
本当のリアクティブプログラミングの詳細は、
NTTの岩塚さん、堅田さんのスライド
Publisher ---[onNext()]--> Subscriber
<--[request()]--
Publisher
の実装Mono
は0/1個、Flux
は0個以上の値を発行可能Flux<String> publisher = Flux.just("aaa", "bbb", "ccc")
.map(String::toUpperCase).repeat(2);
publisher.subscribe(System.out::print);
// AAABBBCCCAAABBBCCC
Mono
やFlux
が利用可能に。@RestController
public class EchoController {
@PostMapping("/echo")
Flux<String> upperCase(@RequestBody Flux<String> body) {
return body.map(String::toUpperCase);
}
}
Flux
をSSEのStreamとして解釈@GetMapping("/infinite")
Flux<Long> infinite() {
return Flux.interval(Duration.ofSeconds(1));
}
curl http://... -H "Accept: text/event-stream"
data:0
data:1
data:2
...
以下のコンセプトの新たなWebフレームワーク
java.util.function
やjava.util.stream
などの関数スタイル記述RouterFunction
とHandlerFunction
の組み合わせ
RequestPredicates
を使用@RequestMapping
相当RouterFunction<ServerResponse> router = RouterFunctions.route(
RequestPredicates.GET("/func1"), handler1)
.andRoute(RequestPredicates.GET("/func2"), handler2);
@RequestMapping
が付与されたメソッド)に相当HandlerFunction<ServerResponse> handler = req -> {
return ServerResponse.ok().body(
Mono.just(req.queryParam("query").get()),
String.class);
};
ServerRequest
: RouterFunction
から取得可能ServerResponse
: HandlerFunction
の戻り値へ返却 RouterFunction
をBean化することで有効になる@Bean
RouterFunction<ServerResponse> router() {
return RouterFunctions.route(POST("/func"),
req -> ServerResponse.ok().body(
req.bodyToFlux(String.class)
.map(String::toUpperCase), String.class));
}
HandlerInterceptor
に相当@Bean
RouterFunction<ServerResponse> routerWithFilter() {
return RouterFunctions.route(POST("/filter1"),
req -> ServerResponse.ok().body(
req.bodyToFlux(String.class)
.map(String::toUpperCase), String.class))
.andRoute(POST("/filter2"),
req -> ServerResponse.ok().body(
req.bodyToFlux(String.class), String.class))
.filter((req, handler) -> {
System.out.println(req.headers().contentLength());
return handler.handle(req);
});
}
@RequestMapping
があるのになぜ?
null
の可能性のあるAPIは全てOptional
型で返却Serializable
制約の廃止save(..)
-> saveAll(..)
findOne(..)
-> findById(..)
MyRepositoryCustom
-> MyRepositoryImpl
ReactiveMongoTemplate template;
Flux<Person> flux = template.find(
new Query(where("_id").is(person.getId())), Person.class);
flux.subscribe(System.out::println);
<S extends T> Mono<S> save(S entity);
<S extends T> Flux<S> saveAll(Publisher<S> entityStream);
Mono<T> findById(ID id);
Flux<T> findAll();
Mono<Long> count();
...
Data Source | Reactive Support |
---|---|
JPA(JDBC) | NG |
Redis | OK |
MongoDB | OK |
Apache Cassandra | OK |
Couchbase | OK |
次のセッションにてご紹介!