Submit Search
Upload
Writing Spring WebFlux more esay with kotlin
•
Download as PPTX, PDF
•
1 like
•
1,566 views
賢太郎 前多
Follow
JJUG CCC 2018 Fall Lightning Talk
Read less
Read more
Software
Report
Share
Report
Share
1 of 21
Download now
Recommended
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
土岐 孝平
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
Masatoshi Tada
Spring Bootの本当の理解ポイント #jjug
Spring Bootの本当の理解ポイント #jjug
Masatoshi Tada
What's new in Spring Batch 5
What's new in Spring Batch 5
ikeyat
Web api開発をするなら ドキュメントは自動生成にしておこう__ph_per_kaigi2021_
Web api開発をするなら ドキュメントは自動生成にしておこう__ph_per_kaigi2021_
Akito Tsukahara
世界最強のソフトウェアアーキテクト
世界最強のソフトウェアアーキテクト
Yahoo!デベロッパーネットワーク
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー
ssuser070fa9
これからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきこと
土岐 孝平
Recommended
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
土岐 孝平
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
Masatoshi Tada
Spring Bootの本当の理解ポイント #jjug
Spring Bootの本当の理解ポイント #jjug
Masatoshi Tada
What's new in Spring Batch 5
What's new in Spring Batch 5
ikeyat
Web api開発をするなら ドキュメントは自動生成にしておこう__ph_per_kaigi2021_
Web api開発をするなら ドキュメントは自動生成にしておこう__ph_per_kaigi2021_
Akito Tsukahara
世界最強のソフトウェアアーキテクト
世界最強のソフトウェアアーキテクト
Yahoo!デベロッパーネットワーク
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー
ssuser070fa9
これからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきこと
土岐 孝平
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
yoshiaki iwanaga
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
Masatoshi Tada
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
shinjiigarashi
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
Y Watanabe
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
mosa siru
コンテナ環境でJavaイメージを小さくする方法!
コンテナ環境でJavaイメージを小さくする方法!
オラクルエンジニア通信
こんなに使える!今どきのAPIドキュメンテーションツール
こんなに使える!今どきのAPIドキュメンテーションツール
dcubeio
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
Hiroshi Tokumaru
例外設計における大罪
例外設計における大罪
Takuto Wada
さくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組み
Takeshi Ogawa
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
Taku Miyakawa
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
Railsで作るBFFの功罪
Railsで作るBFFの功罪
Recruit Lifestyle Co., Ltd.
Keycloak拡張入門
Keycloak拡張入門
Hiroyuki Wada
マイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチ
増田 亨
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
Masatoshi Tada
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
onozaty
Serverless時代のJavaについて
Serverless時代のJavaについて
Amazon Web Services Japan
More Related Content
What's hot
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
yoshiaki iwanaga
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
Masatoshi Tada
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
shinjiigarashi
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
Y Watanabe
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
mosa siru
コンテナ環境でJavaイメージを小さくする方法!
コンテナ環境でJavaイメージを小さくする方法!
オラクルエンジニア通信
こんなに使える!今どきのAPIドキュメンテーションツール
こんなに使える!今どきのAPIドキュメンテーションツール
dcubeio
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
Hiroshi Tokumaru
例外設計における大罪
例外設計における大罪
Takuto Wada
さくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組み
Takeshi Ogawa
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
Taku Miyakawa
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
Railsで作るBFFの功罪
Railsで作るBFFの功罪
Recruit Lifestyle Co., Ltd.
Keycloak拡張入門
Keycloak拡張入門
Hiroyuki Wada
マイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチ
増田 亨
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
Masatoshi Tada
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
onozaty
Serverless時代のJavaについて
Serverless時代のJavaについて
Amazon Web Services Japan
What's hot
(20)
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
コンテナ環境でJavaイメージを小さくする方法!
コンテナ環境でJavaイメージを小さくする方法!
こんなに使える!今どきのAPIドキュメンテーションツール
こんなに使える!今どきのAPIドキュメンテーションツール
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
例外設計における大罪
例外設計における大罪
さくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組み
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
Railsで作るBFFの功罪
Railsで作るBFFの功罪
Keycloak拡張入門
Keycloak拡張入門
マイクロサービス 4つの分割アプローチ
マイクロサービス 4つの分割アプローチ
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
Serverless時代のJavaについて
Serverless時代のJavaについて
Writing Spring WebFlux more esay with kotlin
1.
Spring WebFluxを 簡単に書きたい 前多(twitter @kencharos) JJUG
CCC 2018 Fall LT
2.
About Me • 設計と実装してる人 •
Java ときどき C# • 最近 • 「GraalVM の native image を使って Java で爆速 Lambda の夢を見る」 • https://qiita.com/kencharos/items/69e43965515f368bc4a3
3.
WebFlux の使いどころ • 複数の非同期処理のフローを簡単に記述できる •
例えば 3つの WebAPI 呼び出しを順番に呼び出 したり、一部を並行(同時)にしたり、、 “hello” “world” “!!!" “hello” “world” “!!!” //WebAPI 呼び出しの例 public Mono<String> callApi() { return WebClient.create("http://xxxxx/hello") .get().retrieve().bodyToMono(String.class); }
4.
APIを逐次実行にする例 • flatMap で3つのMonoを順次実行 @GetMapping("/java/rx_seq") public
Mono<String> Seq() { // 逐次実行 Mono<String> hello = helloApi.callApi(); Mono<String> world = worldApi.callApi(); Mono<String> exclamation = exclamationApi.callApi(); return hello .flatMap(h -> world .flatMap(w -> exclamation .map(e -> h + w + e))); }
5.
APIの一部を並行にする例 • Zip で2つのMonoを待ち合わせして、その後 flatMap @GetMapping("/java/rx_seq") public
Mono<String> Par() { // 一部並列実行 Mono<String> hello = helloApi.callApi(); Mono<String> world = worldApi.callApi(); Mono<String> exclamation = exclamationApi.callApi(); return Mono.zip(hello, world) .flatMap(hw -> exclamation .map(e -> hw.getT1() + hw.getT2() + e)); }
6.
本当に簡単? • スレッドとかブロッキングとかを考えなくてい いので楽 • @Async
とか使わなくていいので楽 • 非同期処理の待ち合わせも楽 • とはいえ、従来のプログラムの書き方とは結構 違う • flatMap がネストしだすと少々見づらい • もっと楽にできないか??
7.
Kotlin のコルーチンを使う • コルーチンは処理を途中で止めたり再開したり する機能 •
Java だと Project Loom の Fiberで入るかも? • コルーチンはKotlin1.3 から標準化 • Spring5 から Kotlin 正式対応 • Reactor のコルーチン対応ライブラリ kotlinx-coroutines-reactor がある
8.
コルーチンで逐次処理の例 • mono スコープと
awaitXxx を使うと 複数のMonoを一つに結合できる @GetMapping("seq") fun seqWithCoroutine():Mono<String> = GlobalScope.mono { // awaitFirst で、 Monoを コルーチンに val hello: String = helloApi.callApi().awaitFirst() val world: String = worldApi.callApi().awaitFirst() val exclamation: String = exclamationApi.callApi().awaitFirst() "$hello $world $exclamation" } monoスコープ で囲む MonoにawaitFirstでコルーチン化。 Monoの中の結果のString を取得で きる この値(3 APIの呼び出し結果の連結)が 最終的な戻り値になる
9.
コルーチンで並行化の例 • asyncで一部を非同期実行できる @GetMapping("par") fun parWithCoroutine():Mono<String>
= GlobalScope.mono { // start helloApi and worldApi tasks in asynchronous. val helloDeferred = async { helloApi.callApi().awaitFirst() } val worldDeferred = async { worldApi.callApi().awaitFirst() } // join 2 tasks val hello: String = helloDeferred.await() val world: String = worldDeferred.await() val exclamation = exclamationApi.callApi().awaitFirst() "$hello $world $exclamation" } async スコープ で非同期処理 開始 非同期処理の 結果は await で取得
10.
コルーチンの Pros/Cons • Pros •
同期処理っぽく書ける(flatMapが消えた) • 通常の kotlinの制御構文が使える(if, for, try/catch) • JavaScript/C# の async/await に近い感じ • async でカジュアルに一部を非同期処理にできる • Cons • awaitの呼び出しごとに Rxの subscribe が実行されて いる • Rx の文脈をコルーチンの非同期処理に置き換えてしまう • 他には?
11.
Arrowライブラリを使う • https://arrow-kt.io/ • Scala
の関数型ライブラリ Scalaz, Cats のような 関数型プログラミングの機能(モナドとか)を Kotlinに持ち込む • Reactor 用の拡張を使うと、 Mono, Flux を MonoK, FluxK に変換して モナドにできる
12.
Arrowで逐次処理の例 • 大体の記述はコルーチンと似ている • bindingスコープ(モナド記法),
k(), bind() を使う @GetMapping("monad_seq") fun seqWithMonad():Mono<String> = MonoK.monad().binding { // K() is buidler from Mono to MonoK. MonoK is Monad of Mono in Arrow. // bind() is flatMap as Coroutine. val hello: String = helloApi.callApi().k().bind() val world: String = worldApi.callApi().k().bind() val exclamation: String = exclamationApi.callApi().k().bind() "$hello $world $exclamation" }.value() K()でMonoを MonoKに value()で MonoKをMono に戻す 最終的な 戻り値 bind() でMono の中の String を取得できる
13.
Arrow で並行処理 • Mono.zip
で待ち合わせしたMonoをbindする • Arrowだけで 並行化する方法を調査中 @GetMapping(“monad_par”) fun parWithMonad():Mono<String> = MonoK.monad().binding { val hMono = helloApi.callApi() val wMono = worldApi.callApi() // 並列化は Mono zip を使うしかないっぽい val helloWorld = Mono.zip(hMono, wMono).map { it.t1 + it.t2 }.k().bind() val exclamation = exclamationApi.callApi().k().bind() "$helloWorld $exclamation" }.value()
14.
ArrowのPros/Cons • Pros • bindを使って、同期処理っぽく書ける •
bind 呼び出しは flatMap の呼び出しに置き換わるの で Rx の文脈は保たれる • Arrowの他の機能との統合(後述) • モナド完全に理解した • Cons • モナド全然わからん • 関数型プログラミングの理解が必須 • Mono.zip の代替手段が(今のところ)なさそう • アプリカティブなだけの Monoがなさそう
15.
ここまでまとめ • Kotlinなら WebFlux
が使いやすくなるかもよ • バックプレッシャー周りは継続調査
16.
(おまけ) Arrow の
Either • Either は成功か失敗かのどちらかの表現 • 例外の代わりに使うことが多い • ArrowのEither はモナドなので合成可能 fun aToI(s:String):Either<NumberFormatException, Int> { if (s.matches("^[0-9]+$".toRegex())) { return Either.right(Integer.parseInt(s)) } else { return Either.left(NumberFormatException("invalid string")) } } val result = aToI("123") when(result) { is Either.Right -> print("OK " + result.b) is Either.Left -> print("NG" + result.a.message) } Right(成功) Left(失敗)
17.
MonoKとEitherが組み合わさると • 非同期処理の結果に Either
を使って失敗の可能 性を表現したい場合、Mono(K)とEither を組み 合わせた型ができる fun callApiOrError(name:String):MonoK<Either<Throwable, String>> {///}
18.
モナドのネストは見づらい • MonoKのbindでEither が取れてしまう •
EitherからStringを取るとモナドがネストする val resEither = MonoK.monad().binding { val helloEither:Either<Throwable, String> = helloApi.callApiOrError(query).bind() val worldEither = worldApi.callApiOrError(query).bind() val exclamationEither = exclamationApi.callApiOrError(query).bind() // モナドにモナドがダブってしまう Either.monadError<Throwable>().binding { val hello:String = helloEither.bind() val world:String = worldEither.bind() val exclamation:String = exclamationEither.bind() "$hello $world $exclamation" }.fix() }.value()
19.
EitherT で MonoK<Either>
を合体する • EitherT (モナドトランスフォーマー)を使う と、モナドのネストが消え、従来通りにかける • bind でMono, Eitherの両方を一発ではがす • bindがどこかで失敗(=Either.Leftの発生)するとその 場で評価を停止し、MonoK(Either.Left)を返す • 全て成功した場合は、MonoK(Either.Right)を返す val result = EitherT.monad<ForMonoK, Throwable>(MonoK.monad()).binding { val hello:String = EitherT(helloApi.callApiOrError(query)).bind() val world:String = EitherT(worldApi.callApiOrError(query)).bind() val exclamation = EitherT(exclamationApi.callApiOrError(query)).bind() "$hello $world $exclamation" }
20.
最終的な変換処理は必要 • 最終的に Mono<Either<T>>
をちゃんと変換する コードは必要 • 機械的に書ける内容なので、 Mono<Either<T>> をコ ントローラの戻り値にして、Spring 側でハンドリン グするようにできるはず val res:Mono<Either<Throwable, String>> = result.fix().value().value() return res.map { when(it){ is Either.Right -> ResponseEntity.ok().body(it.b) is Either.Left -> ResponseEntity.badRequest().body(it.a.message) } }
21.
おしまい • Kotlin +
Arrow で Functional Reactive Spring の夢 が見よう! • ソース • https://github.com/kencharos/webflux-coroutine- arrow-sample • Arrow の Either についてはアドカレ書いてます • https://qiita.com/kencharos/items/6fd0a9e92363b08c0340 • 「例外だけに頼らない Kotlinのエラーハンドリング」
Editor's Notes
Spring Fluxの使いどころはMonoやFluxで表す非同期処理が複数ある場合、そのつなぎ方逐次や同時など色々書けることだと思います。
3つの非同期処理を順番に呼び出す場合、flatMapでつなげます。
一部を並列化したい場合は、zipで二つのMonoをくっつけます
Reactorならスレッドとかasyncとか使わなくていいので、楽だとは思いますが、flatMap慣れないとつらいですよね。もっと簡単に書けないでしょうか
で、唐突にKotlinが出てきます。Kotlinのコルーチンは処理の停止・再開を行う機能で非同期処理の代わりに使えます。 Reactor 拡張があるのでこれを使ってみます。
Monoを順番に呼び出す場合は、スコープのなかでawait を使います。Await を使うとMonoの中にあるString が取れるのでそれを連結した値が、最終的なMonoになります。
並列化したい場所、並列にしたい部分を async で囲んで、await で取得すればOKです。
コルーチン使うと、JSのasyc.await みたいな同期的な書き方ができます。Try-catchもできます。 一方で、awaitするごとに Rxのsubscribe 読んでるみたいなので、Rxのやり方を壊してる感じがします。他の方法も見てみます。
Kotlinには Arrow という関数型のライブラリがあります。いわゆるモナドというやつです。
コルーチンみたいに、スコープの中で、bind を使うと Monoの中のStringが取れます。またbindは flatMap と同じです。
並列にしたい場合は、 Monoのzipの後に bind しないといけないので、そこは同じです。
Arrow の bindは、flatMapと同じなので、同期処理みたいに書きつつも、Rxとやっていることが同じになります。 モナドすごいと同時に、全然わからんみたいなになりがちなので、関数型プログラムの知識がある程度いります。聞いて下さい。
ここで一旦まとめると、 Kotlinなら WebFlux楽できそう。バックプレッシャーとかは継続して調査という感じです。
時間が余ってれば、 もう少しArrowの話を。関数型で例外投げるみたいなことをした場合、 Eitherという型を使います。 Rightが成功、Leftが失敗でどちらかだけを持つというデータです。
失敗するかもしれない、非同期処理の結果を示したくなると、こんな感じで、 MonoとEitherが組み合わさります。
で、これをスコープで合成しようとすると、 bindして取れる値が Either なのでもう一度 スコープ作ってbindしないと Stringが取れないわけです。
ここで登場するのが、モナドトランスフォーマーという機能で、 EitherTというトランスフォーマーで、Mono,Eitherを囲んで bind すると、両方を一気にはがして Stringが取れます。 途中の Eitherが失敗したら、その場でエラーになってくれます。大体今までと同じように書けます。
ただ、最終的に Mono,Either の適切は処理はいるので、そこはフレームワークの内部でうまくやるようにすると、いい感じになるんじゃないかと思ってます。 上みたいに、成功ならOK、失敗なら badRequestにするとかね。
おしまいです。Functional reactive Spring ができそうという話でした。 スライドとソースは公開するので、気になった人はじっくり見てみてください。
Download now