Spring Web Flux を少しさわってみただけの話
Spring 5 から Reactive Web というのになるらしく、サーバーの性能が落ちにくくなると聞いた(違うかもしれない)ので、 家で試してみることにした。
環境
- Spring Boot: 2.0.0.RC1
- Java: 1.8
ビルドファイル
以下の curl コマンドで取得できるもの
curl https://start.spring.io/build.gradle -d dependencies=security,webflux -d bootVersion=2.0.0.RC1
なお、依存ライブラリーは次のようになっている
dependencies {
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-webflux')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('io.projectreactor:reactor-test')
testCompile('org.springframework.security:spring-security-test')
}
ハンドラーファンクション
リクエストをさばくために、 org.springframework.web.reactive.function.server.ServerRequest を受け取って、 reactor.core.publisher.Mono または reactor.core.publisher.Flux を返す関数、または メソッドを作る
// クラス名は MyHandler Mono<ServerResponse> hello(final ServerRequest serverRequest) { return ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON) .body( Mono.just(new Message("hello", OffsetDateTime.now(ZoneId.of("Z")))), Message.class); }
@Value static class Message { final String text; final OffsetDateTime time; }
ルーターファンクション
ハンドラーファンクションに対して、URLをマッピングする、ルーターファンクション(org.springframework.web.reactive.function.server.RouterFunction)をBean登録する
// クラス名は MyConfig @Bean RouterFunction<ServerResponse> routerFunction( final SpringWebfluxDemoApplication springWebfluxDemoApplication) { return route(GET("/hello"), myHandler::hello); }
なお、このメソッドのある MyConfig クラスには @org.springframework.web.reactive.config.EnableWebFlux アノテーションをつける
@EnableWebFlux @Configuration public class MyConfig { // 省略 }
セキュリティ
元々セキュリティをつけようとは思っていなかったのだが、間違えてつけてしまったので、その設定もしてみる
Reactive web ではないアプリケーションの場合は UserDetailsService を Bean 登録していたが、
Reactive web であるアプリケーションの場合には ReactiveUserDetailsService を Bean 登録する
ドキュメントを読んでいると、 MapReactiveUserDetailsService なるクラスがあるので、そちらを利用する
@Bean ReactiveUserDetailsService userDetailsService() { final UserDetails userDetails = User.withDefaultPasswordEncoder() .username("foo") .password("bar") .roles("BAZ", "QUX") .build(); return new MapReactiveUserDetailsService(userDetails); }
いつもの
あとはいつものとおり、 @SpringBootApplication アノテーションをつけたクラスと、 main メソッドを作る
@SpringBootApplication
public class App {
public static void main(String... args) {
SpringApplication.run(App.class, args);
}
}
動かしてみた
アプリケーションを起動して curl でアクセスしてみる

$ curl -v http://localhost:8080/hello -H "Authorization: Basic $(echo -n 'foo:bar' | openssl base64)"
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /hello HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> Authorization: Basic Zm9vOmJhcg==
>
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< Content-Type: application/json
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1 ; mode=block
<
* Connection #0 to host localhost left intact
{"text":"hello","time":1518024505.503000000}
まあ、なんか、動いた
OffsetDateTime のところがタイムスタンプになっていたので Jackson のカスタマイズ方法をドキュメントから探して
CodecCustomizer を Bean 登録すればよいことがわかったのだが、これはうまくいかなかった…
@Bean CodecCustomizer addJacksonJsr310Support() { return configurer -> configurer.customCodecs() .encoder(new Jackson2JsonEncoder(objectMapper(), MimeTypeUtils.APPLICATION_JSON)); }
おわり