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)); }
おわり