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 -> MyRepositoryImplReactiveMongoTemplate 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 |
次のセッションにてご紹介!