SlideShare a Scribd company logo
Reactive Webアプリケーション
- そしてSpring 5へ
Toshiaki Maki (@making)
JJUG CCC 2015 Fall
2015-11-30 #jjug_ccc
#ccc_ef3
聞いたことあります?
• Reactive Programming?
• Reactive Manifest?
• Reactive Streams?
• Reactive Extensions?
• Reactive ... ?
• Reactiveが重要視されてきた背景
• Reactive Streams
• Reactive Extensions
• Spring 5
今日話すこと
Reactive
Extensions(Rx)
Reactive
Programming
Reactive
Streams
Reactor
RxJava
Spring 5
プロラミング
パラダイム
仕様(?)
今日話すこと
実装
ライブラリ
Spring
Framework
元ネタ
http://www.slideshare.net/SpringCentral/reactive-web-applications-53170985
http://www.slideshare.net/SpringCentral/introduction-to-reactive-programming
Reactiveが重要視され
てきた背景
Amdalの法則
https://en.wikipedia.org/wiki/Amdahl%27s_law
Amdalの法則
https://en.wikipedia.org/wiki/Amdahl%27s_law
プログラムの並列化による速度の向上は、
プログラムの逐次処理部分によって制限される
Amdalの法則
https://en.wikipedia.org/wiki/Amdahl%27s_law
プログラムの並列化による速度の向上は、
プログラムの逐次処理部分によって制限される
プログラム中の
並列実行可能部分が50%
だと、いくら並列度を増や
しても2倍の性能向上し
か見込めない
スケールアウト戦略
• メモリばかり消費してCPUに空き…
✦ 大量のスレッドプール
✦ブロッキングI/O
ブロッキングコードを
書いていては
ハードにいくら金をかけても
性能向上に限界がある
Blocking is evil
• ブロッキングコードは並列化の妨げ
• 2大ブロッキング
• リクエストの受信待ち/レスポンス
の送信待ち
• DBクエリの結果待ち
Blocking is evil
• ブロッキングコードは並列化の妨げ
• 2大ブロッキング
• リクエストの受信待ち/レスポンス
の送信待ち
• DBクエリの結果待ち
InputStream
OutputStream
JDBC
• IoT
• マイクロサービス
今後のトレンド
• IoT
• マイクロサービス
低速で膨大な
リクエスト
が予想される
今後のトレンド
• IoT
• マイクロサービス
低速で膨大な
リクエスト
が予想される
今後のトレンド
Blocking == 💴
Non-Blocking!
• 命令型ではなくリスナー/コールバックス
タイル
• スレッド数を少なく
• →省メモリ
• →コンテキストスイッチを減らす
• →CPUを有効活用
Reactiveプログラミング
• 命令型と異なるプログラミングパラダイム
• 連続的なデータをイベントハンドラで処理する
• データフロー(データ同士の関係性)に着目した
イベントドリブンなプログラミング
Reactiveプログラミング
• 命令型と異なるプログラミングパラダイム
• 連続的なデータをイベントハンドラで処理する
• データフロー(データ同士の関係性)に着目した
イベントドリブンなプログラミング
ノンブロッキングコードを書く
のに向いている
最も身近なReactiveプログラミング?
最も身近なReactiveプログラミング?
最も身近なReactiveプログラミング?
最も身近なReactiveプログラミング?
最も身近なReactiveプログラミング?
A, Bの変更に伴い
Cも変わる
データフロー
A
B 2
+ C
A, Bの変更に伴い
Cも変わるhttps://speakerdeck.com/okapies/reactive-streams-ru-men-number-jjug
イベントストリーム
x2
+
1  2      4      3
9    6    8    6    5    9
8      4      2  64      2      1  3
A
B
C
イベントストリーム
x2
+
1  2      4      3
9    6    8    6    5    9
8      4      2  64      2      1  3
A
B
C
イベントストリーム
x2
+
1  2      4      3
9    6    8    6    5    9
8      4      2  64      2      1  3
A
B
C
イベントストリーム
x2
+
1  2      4      3
9    6    8    6    5    9
8      4      2  64      2      1  3
A
B
C
イベントストリーム
x2
+
1  2      4      3
9    6    8    6    5    9
8      4      2  64      2      1  3
A
B
C
イベントストリーム
x2
+
1  2      4      3
9    6    8    6    5    9
8      4      2  64      2      1  3
A
B
C
イベントストリーム
x2
+
1  2      4      3
9    6    8    6    5    9
8      4      2  64      2      1  3
A
B
C
命令型
int A = 3;
int B = 3;
int C = A + B * 2; // 9
B = 1;
A, Bが変更されても
Cは変わらない
JavaFXの場合
@FXML

Spinner<Integer> valueA;

@FXML

Spinner<Integer> valueB;

@FXML

Label valueC;
private void bind() {

IntegerProperty a = new SimpleIntegerProperty(0);

IntegerProperty b = new SimpleIntegerProperty(0);

NumberBinding c = a.add(b.multiply(2)); // c = a + 2 * b

a.bind(this.valueA.valueProperty());

b.bind(this.valueB.valueProperty());

valueC.textProperty().bind(c.asString());

}
http://aoe-tk.hatenablog.com/entry/2015/07/12/173402
Reactive Webアプリケーション - そしてSpring 5へ #jjug_ccc #ccc_ef3
Reactive Webアプリケーション - そしてSpring 5へ #jjug_ccc #ccc_ef3
A, Bの変更に伴い
Cも変わる
Reactive Webアプリケーション
Repository
DBService
Controller
Reactive Webアプリケーション
Repository
DBService
Controller
Reactive Webアプリケーション
Repository
DBService
Controller
Blocking Blocking
Reactive Webアプリケーション
Repository
DBService
Controller
Blocking BlockingBlocking
他サービス呼び出し
Reactive Streams
Reactive Streams
• http://www.reactive-streams.org/
• 非同期ストリームの標準仕様
• BackPressure付き
Reactive Streamsの動機
1. 技術面: データを送り側の勢いが受け
取り側の処理速度より速い場合に、デー
タが れることを防ぎたい
(BackPressure)
2. 開発面: 似たような機能(API)を持つ製
品群の相互互換性を持たせたい
関わっている会社
• Typesafe
• Pivotal
• Netflix
• RedHat
• など
関わっている会社
• Typesafe ... Akka Streams
• Pivotal ... Reactor
• Netflix ... RxJava
• RedHat ... Vert.x
• など
Reactive Streamsが提供するもの
• 4つのインターフェース
• 仕様ドキュメント
• TCK (仕様をテストするJUnitの親クラス)
public interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
public interface Subscription {
public void request(long n);
public void cancel();
}
public interface Subscriber<T> {
public void onSubscribe(Subscription s);
public void onNext(T t);
public void onError(Throwable t);
public void onComplete();
}
public interface Processor<T, R> extends
Publisher<T>, Subscriber<R> {}
org.reactivestreams
public interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
public interface Subscription {
public void request(long n);
public void cancel();
}
public interface Subscriber<T> {
public void onSubscribe(Subscription s);
public void onNext(T t);
public void onError(Throwable t);
public void onComplete();
}
public interface Processor<T, R> extends
Publisher<T>, Subscriber<R> {}
org.reactivestreams
BackPressure
呼び出し順
onSubscribe onNext* (onError | onComplete)?
Subscription SubscriberPublisher Application
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
onNext(●)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
onNext(●)
onNext(●)
request(4)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
onNext(●)
onNext(●)
request(4)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
onNext(●)
onNext(●)
request(4)
onNext(●)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
onNext(●)
onNext(●)
request(4)
onNext(●)
onNext(●)
onComplete()
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(Long.MAX_VALUE)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(Long.MAX_VALUE)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(Long.MAX_VALUE)
onNext(●)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(Long.MAX_VALUE)
onNext(●)
onNext(●)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(Long.MAX_VALUE)
onNext(●)
onNext(●)
onNext(●)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(Long.MAX_VALUE)
onNext(●)
onNext(●)
onNext(●)
onNext(●)
onNext(●)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(Long.MAX_VALUE)
onNext(●)
onNext(●)
onNext(●)
onNext(●)
onNext(●)
onComplete()
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
onNext(●)
onNext(●)
request(4)
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
onNext(●)
onNext(●)
request(4)💣
💥
Subscription
subscribe(Subscriber)
SubscriberPublisher Application
onSubscribe(Subscription)
request(1)
onNext(●)
request(2)
onNext(●)
onNext(●)
request(4)
onError(Throwable)
💣
💥
RxJavaからinspired
RxJava Reactive Streams
Observable<T> Publisher<T>
Observer<T> Subscriber<T>
Subscription Subscription
Non BlockingなAPI
• TやList<T>の代わりにPublisher<T>を返す
Blocking Non Blocking
User
get(String name)
Publisher<User>
get(String name)
List<User>
allFriends(User user)
Publisher<User>
allFriends(User user)
実装例 (Publisher)
public class IntPublisher implements Publisher<Integer> {

@Override

public void subscribe(Subscriber<? super Integer> s) {

s.onSubscribe(new Subscription() {

Iterator<Integer> it = IntStream.range(0, 10)
.boxed().iterator();

@Override

public void request(long n) {

for (int i = 0; i < n; i++) {

if (it.hasNext()) {

s.onNext(it.next());

} else {

s.onComplete();

break;

}}}

@Override

public void cancel() {}

});}}
実装例 (Subscriber)public class IntSubscriber implements Subscriber<Integer> {

Subscription subscription;

int req = 1; // AtomicIntegerにすべき

@Override public void onSubscribe(Subscription s) {

subscription = s; s.request(req);

}

@Override public void onNext(Integer integer) {
System.out.println("Next -> " + integer);

if (--req == 0) {

req = new Random().nextInt(10) + 1;

subscription.request(req);
}

}

@Override public void onError(Throwable t) { /**/ }

@Override public void onComplete() {
System.out.println("Complete!");

}

}

使用例
Publisher<Integer> publisher = new IntPublisher();
Subscriber<Integer> subscriber = new IntSubscriber();
publisher.subscribe(subscriber);
// Next -> 1
// Next -> 2
// Next -> 3
// Next -> 4
// Next -> 5
// Next -> 6
// Next -> 7
// Next -> 8
// Next -> 9
// Next -> 10
// Complete!
使用例
Publisher<Integer> publisher = new IntPublisher();
Subscriber<Integer> subscriber = new IntSubscriber();
publisher.subscribe(subscriber);
// Next -> 1
// Next -> 2
// Next -> 3
// Next -> 4
// Next -> 5
// Next -> 6
// Next -> 7
// Next -> 8
// Next -> 9
// Next -> 10
// Complete!
IntPublisher/IntSubscriberは
インターフェースを実装しているだけ
で、実は仕様を満たしていない
(TCKを通らない)
Hot / Cold
• Hot Stream
• ずっと続いていて途中から見はじめるもの
• 株価情報、タイムライン、マウスイベント、タイマー
イベント、WebSocket、Server-Sent Events、メッ
セージキュー
• Cold Stream
• 再現可能で、最初から最後まで見れるもの
• 配列・リスト、ファイル、データベース、計算結果
(Future)
Reactive Streamsの仕様
• Subscriberは非同期でも同期でも
よい。ただし、ノンブロッキングで
ないといけない
実装プロダクト(フレームワーク)
• Reactor (Pivotal)
• RxJava (Netflix)
• Akka Streams (Typesafe)
• Vert.x (Redhat)
• Ratpack
• Quasar
http://www.reactive-streams.org/announce-1.0.0
実装データアクセスライブラリ
• MongoDB (公式)
• Apache Kafka
• Rabbit MQ (Scalaのみ)
• Slick3 (Scala)
• CouchDB (RxJava only)
• PostgreSQL (RxJava only、開発中?)
• Spark (検討中? SPARK-10420)
• など
MongoDB
• http://mongodb.github.io/mongo-java-driver-reactivestreams/
• MongoDB公式でReactive Streams API
がサポートされている
• チュートリアルがあるのでわかりやすい
MongoDB
MongoClient client = MongoClients.create(

"mongodb://localhost");

MongoDatabase db = client.getDatabase("mydb");

MongoCollection<Document> collection =
db.getCollection("test");
// Insert
Document doc = new Document("message", "Hello!");

Publisher<Success> insert = collection.insertOne(doc);

insert.subscribe(new PrintSubscriber<>("result=%s"));
// Select
Publisher<Document> docs = collection.find();

docs.subscribe(new PrintDocumentSubscriber());
MongoDB
// Bulk Operation
PrintSubscriber<BulkWriteResult> subscriber
= new PrintSubscriber<>("Bulk write results: %s");

collection.bulkWrite(Arrays.asList(

new InsertOneModel<>(new Document("_id", 4)),

new InsertOneModel<>(new Document("_id", 5)),

new InsertOneModel<>(new Document("_id", 6)),

new UpdateOneModel<>(new Document("_id", 1),
new Document("$set", new Document("x", 2))),

new DeleteOneModel<>(new Document("_id", 2)),

new ReplaceOneModel<>(new Document("_id", 3),
new Document("_id", 3).append("x",4))))
.subscribe(subscriber);
Apache Kafka
• https://github.com/softwaremill/reactive-kafka
• Scalaで実装されている。Java用API
も用意されている。
Apache Kafka
ReactiveKafka kafka = new ReactiveKafka();

ActorSystem system =
ActorSystem.create("ReactiveKafka");
Publisher<MessageAndMetadata<byte[], String>> topicA
= kafka.consume(new PropertiesBuilder.Consumer(
broker, zk, "topicA","group", decoder)
.build(), system);
topicA.subscribe(subscriber);
PostgreSQL
• https://github.com/alaisi/postgres-async-
driver
• https://github.com/mauricio/postgresql-async
PostgreSQL
Db db = new ConnectionPoolBuilder()
.hostname("localhost").port(5432).database("demo")
.username("postgres").password("")
.poolSize(20).build();


// RxJava's Observable
Observable<Row> result =
db.queryRows("select id,value from demo");
result.subscribe(...);
// to Reactive Streams
Publisher<Row> publisher =
RxReactiveStreams.toPublisher(result);
publisher.subscribe(...);
Publisher単体だと使いにくい
• Publisherはただのコールバック
• map、flatMap、merge、filer、take、zip
といっった合成(compose)や変換(transform)
のためのAPIがない → コールバック地獄に
• Publisherはインターフェースでしかないので
実装ライブラリ側で便利なAPIを提供可能。
コールバック地獄
• もっと命令的に書きたい
• ComposableなAPIが欲しい
(Reactive Streamsの範疇外)
Reactive Extensions
Reactive Extensions(Rx)
• 元々はMicrosoftのでErik Meijerによっ
て.NET(LINQ)向け開発されたライブラリ
• Observerパターンでイベントストリームを扱う
• イベントストリームを操作(変換、フィルタ、合成
など)する豊富なAPI群
• 多言語対応(Java, JavaScript, .NET, Swiftなど)
http://reactivex.io/
map
flatMap
filter
take
merge
zip
combileLatest
buffer
RxJava
• Netflix社が開発したRxのJava版
• Observable/Observer
• Observableに対して豊富なOperation APIを提供
Observable.just('a', 'b', 'c')
.take(2)
.map(Character::toUpperCase)
.consume(System.out::print); // AB
RxJava
• バージョン1.0ではReactive Streamsをnativeサポー
トしていない。Publisher <-> Observableアダプ
ターが必要
• バージョン2.0でReactive Streams対応予定
// Publisher <-> Observable
Publisher<String> publisher =
RxReactiveStreams.toPublisher(observable);
Observable<String> observable =
RxReactiveStreams.toObservable(publisher);
Reactor
• Pivotal社が開発
• LMAX Disruptorの高性能なRing Bufferを使用している
• Spring Frameworkの一部の機能で使用されている
• Reactive Streamsの

Publisher + Composable API → reactor.rx.Stream
Streams.just('a', 'b', 'c')
.take(2)
.map(Character::toUpperCase)
.consume(System.out::print); // AB
Reactor Projectshttp://projectreactor.io/docs/reference/#_about_the_project
Reactive StreamsとReactor Streamsの関係
BroadCaster
Action
Stream
Processor
Subscriber Publisher
Consumer
Class
Interface
extends implements
Reactive Streams
Reactor
Promise
Reactor Streamsへの変換
import reactor.rx.Stream;
import reactor.rx.Streams;
// Streamの要素を直接指定(Cold)
Stream<String> stream = Streams.just("a", "b");
// T[]やIterable<T>からStream<T>への変換(Cold)
Stream<String> stream = Streams.from(value);
// Publisher<T>からStream<T>へ変換
Stream<String> stream = Streams.wrap(publisher);
// Subscription.request(Long.MAX_VALUE)相当
// consumeに渡すラムダ式がonNextで実行される
stream.consume(s -> System.out.println(s));
// Subscription.request(2)を繰り返す
stream.capacity(2)
.consume(s -> System.out.println(s));
// デバッグログ出力
stream.log()
.consume(s -> System.out.println(s));
Reactive Streamsの仕様を
簡単に満たすヘルパー
List<Integer> items = /* ... */;
Publisher<Integer> publisher =
PublisherFactory.forEach((subscriber) -> {
Iterator<Integer> iterator
= subscriber.context();
if (iterator.hasNext()) {
subscriber.onNext(iterator.next());
} else {
subscriber.onComplete();
}
}, subscriber -> items.iterator());
reactor.rx.Streamを使うことで
Reactive Streamsを
Reactive Extensionsで操作できる
Kafka + Reactorで足し算
Publisher<MessageAndMetadata<byte[], String>> topicA =
kafka.consume(new PropertiesBuilder.Consumer(
broker, zk, "a", "group", decoder)

.build(), system);

Publisher<MessageAndMetadata<byte[], String>> topicB =
kafka.consume(new PropertiesBuilder.Consumer(
broker, zk, "b", "group", decoder)

.build(), system);


Publisher<Integer> a = Streams.wrap(topicA)
.map(x -> Integer.valueOf(x.message()));

Publisher<Integer> bx2 = Streams.wrap(topicB)
.map(x -> Integer.valueOf(x.message()))
.map(x -> x * 2);


Streams.combineLatest(a, bx2, tpl -> tpl.getT1()+tpl.getT2())

.consume(c -> {

System.out.println("a + b * 2 = " + c);

});
Kafka + Reactorで足し算
$ echo '3' | kafkacat -P -t a -b localhost:9092
$ echo '3' | kafkacat -P -t b -b localhost:9092
$ echo '1' | kafkacat -P -t b -b localhost:9092
a + b * 2 = 5
a + b * 2 = 9
Reactorでコナミコマンド
// Create a "Hot" stream
Broadcaster<String> stream
= Broadcaster.create(Environment.get());
stream.filter(x -> x.length() == 1)
.buffer(10, 1) // 10イベント分を1つずらしでまとめる
.map(s ->
"↑".equals(s.get(0)) && "↑".equals(s.get(1)) &&
""".equals(s.get(2)) && """.equals(s.get(3)) &&
"←".equals(s.get(4)) && "#".equals(s.get(5)) &&
"←".equals(s.get(6)) && "#".equals(s.get(7)) &&
"A".equals(s.get(8)) && "B".equals(s.get(9)))

.consume(isKonami -> {

System.out.println(isKonami ? "Konami!" : "NG");

});
Reactorでコナミコマンド
stream.onNext("A");

stream.onNext("↑");

stream.onNext("↑");

stream.onNext(""");

stream.onNext(""");

stream.onNext("←");

stream.onNext("#");

stream.onNext("←");

stream.onNext("#");

stream.onNext("A");

stream.onNext("B");

stream.onNext("←");
NG
Konami!
NG
コナミコマンド
HotStreamをエミュレート
外部サービス呼び出し (Blocking)
public interface LinkedInService {
List<String> findUsers(String keyword);
LinkedInProfile getConnection(String id);
}
public interface TwitterService {
TwitterProfile getUserProfile(String id);
}
public interface FacebookService {
FacebookProfile getUserProfile(String id);
}
外部サービス呼び出し (NonBlocking)
public interface LinkedInService {
Stream<String> findUsers(String keyword);
Stream<LinkedInProfile> getConnection(String id);
}
public interface TwitterService {
Stream<TwitterProfile> getUserProfile(String id);
}
public interface FacebookService {
Stream<FacebookProfile> getUserProfile(String id);
}
flatMap
linkedInService.findUsers("JJUG")
.take(5)
.flatMap(userName ->

linkedInService.getConnections(userName)
.take(3)
.flatMap(connection -> {

String twitterId = connection.getTwitterId();

Publisher<TwitterProfile> twitterProfile =
twitterService.getUserProfile(twitterId);

String facebookId = connection.getFacebookId();

Publisher<FacebookProfile> facebookProfile =
facebookService.getUserProfile(facebookId);

return Streams.zip(twitterProfile, facebookProfile,
(tp, fp) -> new UserConnectionInfo(
userName, connection, tp, fp));

})
)
.subscribe(System.out::println);
http://www.slideshare.net/SpringCentral/introduction-to-reactive-programming/60
Reactor or RxJava ?
Reactor RxJava
• Reactive Streamsを
Nativeサポート
• Spring連携
• Reactive Extensions
のサブセット
• Reactive Exensionsを
フルセットでサポート
• 他言語対応
• Reactive Streamsはア
ダプター経由
Reactive Streamsのメリット
• 非同期サポートライブラリを作りやすい
Reactive Streamsのメリット
• 非同期サポートライブラリを作りやすい
• async-db-driver
• Publisher/Subscriberのみを使ったコアライブラリ
• async-db-driver-reactor
• ReactorのStreamにラップ
• async-db-driver-rxjava
• RxJavaのObservableにラップ
• ...
https://github.com/ReactiveX/RxJava/wiki/Reactive-Streams#recommended-approach
package com.example.db.driver;
import org.reactivestreams.Publisher;
public class Database {
public Publisher getValue(String key) { /* ... */ }
}
package com.example.db.driver.reactor;
public class Database {
public Stream getValue(String key) {
return Streams.wrap(coreDatabase.getValue(key));
}
}
package com.example.db.driver.rxjava;
public class Database {
public Observable getValue(String key) {
return RxReactiveStreams.toObservable(
coreDatabase.getValue(key));
}
}
RxJava用
Reactor用
Core API
すべてがPublisherで繋がる
Repository
DBService
ControllerPublisher Publisher Publisher
PublisherPublisherPublisher
すべてがPublisherで繋がる
Repository
DBService
ControllerPublisher Publisher Publisher
PublisherPublisherPublisher
すべてがPublisherで繋がる
Repository
DBService
ControllerPublisher Publisher Publisher
PublisherPublisherPublisher
ここ
は?
Spring 5
Spring 5
• Q4 2016
• JDK 9サポート
• Java 8がベースライン
• HTTP 2対応
• Reactive対応
• JUnit5対応
Spring 5
• Q4 2016
• JDK 9サポート
• Java 8がベースライン
• HTTP 2対応
• Reactive対応
• JUnit5対応
Java Webアプリケーション
のReactive対応?
• Servlet APIは至るところでBlocking
• InputStream/OutputStream
• getParameters/getParts
• sendError
• ...
昨今のNoBlocking対応
フレームワーク
• Play Framework
• Vert.x
• Ratpack
• Reactor Net
• RxNetty
脱Servlet API組
↓
Netty利用
Servletはダメな子なのか
Servletはダメな子なのか
• Servlet 3.0 … 非同期処理サポート
Servletはダメな子なのか
• Servlet 3.0 … 非同期処理サポート
• Servlet 3.1 … Non-Blocking APIサ
ポート
Servlet 3.0
非同期処理サポート
void doGet(req, res) {
OutputStream out = res.getOutputStream();
AsyncContext ctx = req.startAsync();
doAsyncREST(req).thenAccept(json -> {
out.write(json);
ctx.complete();
});
}
http://www.slideshare.net/SimoneBordet/servlet-31-async-io
Servlet 3.0
非同期処理サポート
void doGet(req, res) {
OutputStream out = res.getOutputStream();
AsyncContext ctx = req.startAsync();
doAsyncREST(req).thenAccept(json -> {
out.write(json); // Blocking!!
ctx.complete();
});
}
http://www.slideshare.net/SimoneBordet/servlet-31-async-io
Servlet 3.1
Non-Blocking APIサポート
• リクエストの読み込み/レスポンスの書き込みを
Non-Blockingに行うためのAPIが追加された
• 以下のシーンで効果的
• ファイルアップロード/ダウンロード
• 低速ネットワークからの大量アクセス(モバイル、IoT)
void doGet(req, res) {
OutputStream out = res.getOutputStream();
AsyncContext ctx = req.startAsync();
out.setWriteListener(new WriteListener() {
void onWritePossible() {
while (on.isReady()) {
// ...
ctx.complete();
}
}
});
}
http://www.slideshare.net/SimoneBordet/servlet-31-async-io
Hello Worldサーブレット
@WebServlet(urlPatterns = "/hello"
, asyncSupported = true)
public class HelloServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req,
HttpServletResponse resp) {
AsyncContext ctx = req.startAsync(req, resp);
ServletInputStream input = req.getInputStream();
ReadListener readListener =
new ReadListenerImpl(input, resp, ctx);
input.setReadListener(readListener);
}
class ReadListenerImpl implements ReadListener {
// ...
private final StringBuilder sb = new StringBuilder();
public ReadListenerImpl(ServletInputStream input,
HttpServletResponse resp, AsyncContext ctx) {/* ... */}
public void onDataAvailable() throws IOException {
int len = 0; byte b[] = new byte[1024];
while (input.isReady() && !input.isFinished()
&& (len = input.read(b)) != -1) {
sb.append(new String(b, 0, len));
}
}
public void onAllDataRead() throws IOException {
ServletOutputStream output = resp.getOutputStream();
WriteListener writeListener =
new WriteListenerImpl(output, ctx);
output.setWriteListener(writeListener);
}
public void onError(Throwable th) {
ctx.complete(); th.printStackTrace();
}
}
class WriteListenerImpl implements WriteListener {
private final ServletOutputStream output;
private final AsyncContext ctx;
public WriteListenerImpl(ServletOutputStream output,
AsyncContext ctx) {
this.output = output;
this.ctx = ctx;
}
public void onWritePossible() throws IOException {
output.print("Hello World!");
output.flush();
ctx.complete();
}
public void onError(Throwable th) {
th.printStackTrace();
}
}
Block
Servlet
Servlet
ReadListener
WriteListener
Servlet
ReadListener
WriteListener
書くのが辛い
• Non-Blockingの方が5倍コード量が多い
• isReady, isFinishedの制御が難しい
• ついgetParameterするとBlock...
http://www.slideshare.net/SimoneBordet/servlet-31-async-io
Spring Reactive
• Spring 5のReactive対応向け実験プロジェクト
• 開発メンバー
• Rossen Stoyanchev (Spring MVC)
• Stephane Maldini (Reactor, Reactive Streams)
• Arjen Poutsma (MVCのREST対応, Spring WS)
• Sébastien Deleuze (MVCのScriptEngine対応)
• Brian Clozel (MVCの静的リソースハンドリング対応)
https://github.com/spring-projects/spring-reactive
Servlet31HttpHandlerAdapter
• HttpServlet実装
• ReadListener/WriteListenerを
Observerパターンで実装
• Reactive Streams(Publisher/
Subscriber)を使用
• ReadListener→Publisher
• WriteListener→Subscriber
Servlet31HttpHandlerAdapter
https://github.com/spring-projects/spring-reactive/tree/master/src/main/java/org/springframework/http/server/servlet31
Instead of ...
interface ServerHttpRequest extends HttpRequest {
InputStream getBody();
}
interface ServerHttpResponse extends HttpMessage {
OutputStream getBody();
}
Use Publisher
interface ReactiveServerHttpRequest extends HttpRequest {
Publisher<ByteBuffer> getBody();
}
interface ReactiveServerHttpResponse extends HttpMessage {
Publisher<Void> setBody(Publisher<ByteBuffer> pub);
}
Spring MVCのアーキテクチャ
Dispatcher
Servlet
<<IF>>
HandlerAdapter
<<IF>>
HandlerMapping
Handler
(Object)
フレームワーク アプリケーション
org.springframework.web.servletパッケージ
これまでの
Spring MVCのアーキテクチャ
Dispatcher
Servlet
RequestMapping
HandlerAdapter
RequestMapping
HandlerMapping
@RequestMapping
HttpMessageConverter
org.springframework.web.servlet.mvc.method.annotationパッケージ
これまでの
Spring MVCのアーキテクチャ
Dispatcher
Servlet
RequestMapping
HandlerAdapter
RequestMapping
HandlerMapping
@RequestMapping
HttpMessageConverter
org.springframework.web.servlet.mvc.method.annotationパッケージ
所謂、
Controllerクラス
これまでの
Spring Reactiveのアーキテクチャ
<<IF>>
HandlerAdapter
<<IF>>
HandlerMapping
Handler
(Object)
フレームワーク アプリケーション
org.springframework.web.reactiveパッケージ
Servlet31Http
HandlerAdapter
<<IF>>
Reactive
HttpHandeler
Servlet31Http
HandlerAdapter
RequestMapping
HandlerAdapter
RequestMapping
HandlerMapping
@RequsetMapping
Encoder/Decoder
Spring Reactiveのアーキテクチャ
org.springframework.web.reactive.method.annotationパッケージ
Dispatcher
Handler
RequestMapping
HandlerAdapter
RequestMapping
HandlerMapping
@RequsetMapping
Encoder/Decoder
Spring Reactiveのアーキテクチャ
org.springframework.web.reactive.method.annotationパッケージ
Servlet31Http
HandlerAdapter
Dispatcher
Handler
Spring MVCと同じプログラミングモデルで
アプリケーションを記述できる
Spring Reactiveのアプローチ
Reactor Net
ReactorHttpHanderAdapter
RxNetty
RxNettyHttpHandlerAdapter
Undertow
UndertowHttpHandlerAdapter
Servlet31Http
HandlerAdapter
ReactiveStreams
@Controller
Jetty
Tomcat
Publisher
ReactiveHttpHandeler
Spring Reactiveのアプローチ
Reactor Net
ReactorHttpHanderAdapter
RxNetty
RxNettyHttpHandlerAdapter
Undertow
UndertowHttpHandlerAdapter
Servlet31Http
HandlerAdapter
ReactiveStreams
@Controller
Jetty
Tomcat
Publisher
ReactiveHttpHandeler
Servletコンテナ以外の
選択肢もある
Spring MVCのController
@RequestMapping("/")
@ResponseBody
Person hello(@RequestBody Person req) {
// ...
}
これまでの
Spring ReactiveのController
@RequestMapping("/")
@ResponseBody
Publisher<Person> hello(
@RequestBody Publisher<Person> req) {
// ...
}
Reactive Webアプリケーション
Repository
DBService
ControllerPublisher Publisher Publisher
PublisherPublisherPublisher
Reactive Webアプリケーション
Repository
DBService
ControllerPublisher Publisher Publisher
PublisherPublisherPublisher
SpringReactive
ReactiveExtensions
Reactive Streams
絶賛開発中
• Reactive Clientの実装
• Filter相当の実装
• Progressive HTML renderingの検討
Springは
Java EEの代替ではありません
落穂拾い
java.util.concurrent.Flow
• Reactive StreamsがJDK 9に入ります
• Flow.Publisher
• Flow.Subscriber
• Flow.Subscription
• Flow.Processor
• http://openjdk.java.net/jeps/266
• http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java/util/concurrent/Flow.html
@author Doug Lea
j.u.c.Flow <-> Reactive Streams
• ブリッジ作成を検討中
• https://github.com/reactive-streams/reactive-streams-jvm/issues/294
import java.util.concurrent.Flow;
import org.reactivestreams.Publisher;
// j.u.c.Flow -> Reactive Streams
Publisher<T> toReactive(Flow.Publisher<>T);
// Reactive Streams -> j.u.c.Flow
Flow.Publisher<T> toFlow(Publisher<T>);
Servlet 4
• HTTP2とReactive Streams (Back Pressure)の
連携案
• JDK9にj.u.c.Flowが入ったため、御蔵入りの模様
https://java.net/projects/servlet-spec/lists/jsr369-experts/archive/2015-08/message/1
まとめ
• Blocking ==💴な時代がきている
• Non-Blocking化を助けるReactiveなパラダイム
• 非同期ストリーム標準 Reactive Streams
• イベントストリームの変換・合成 Reactive
Extensions
• Reactive Webアプリケーション向けフレームワー
クSpring ReactiveがSpring 5に向けて開発中
まとめ
• Blocking ==💴な時代がきている
• Non-Blocking化を助けるReactiveなパラダイム
• 非同期ストリーム標準 Reactive Streams
• イベントストリームの変換・合成 Reactive
Extensions
• Reactive Webアプリケーション向けフレームワー
クSpring ReactiveがSpring 5に向けて開発中
Spring Framework
を使っていきましょう

More Related Content

PPTX
Spring 5に備えるリアクティブプログラミング入門
PDF
イミュータブルデータモデル(世代編)
PDF
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
PPTX
テストコードの DRY と DAMP
PDF
劇的改善 Ci4時間から5分へ〜私がやった10のこと〜
PDF
トランザクションスクリプトのすすめ
PDF
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
PDF
LineairDB: Fast and Embedded Transactional Key-Value Storage
Spring 5に備えるリアクティブプログラミング入門
イミュータブルデータモデル(世代編)
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
テストコードの DRY と DAMP
劇的改善 Ci4時間から5分へ〜私がやった10のこと〜
トランザクションスクリプトのすすめ
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
LineairDB: Fast and Embedded Transactional Key-Value Storage

What's hot (20)

PDF
async/awaitダークサイド is 何
PDF
それはYAGNIか? それとも思考停止か?
PDF
マイクロにしすぎた結果がこれだよ!
PDF
イミュータブルデータモデル(入門編)
PDF
【Unite 2017 Tokyo】「黒騎士と白の魔王」にみるC#で統一したサーバー/クライアント開発と現実的なUniRx使いこなし術
PDF
[KGC 2012] Online Game Server Architecture Case Study Performance and Security
PDF
Webアプリを並行開発する際のマイグレーション戦略
PDF
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
PDF
Javaのログ出力: 道具と考え方
PDF
Tackling Complexity
PDF
イミュータブルデータモデルの極意
PDF
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
PPTX
世界一わかりやすいClean Architecture
PDF
工数把握のすすめ 〜WorkTimeプラグインの使い方〜
PDF
ストリーム処理を支えるキューイングシステムの選び方
PDF
Spring Boot × Vue.jsでSPAを作る
PDF
ClickHouse導入事例紹介
PDF
ドメイン駆動設計サンプルコードの徹底解説
PPT
UnicodeによるXSSと SQLインジェクションの可能性
PDF
nioで作ったBufferedWriterに変えたら例外になった
async/awaitダークサイド is 何
それはYAGNIか? それとも思考停止か?
マイクロにしすぎた結果がこれだよ!
イミュータブルデータモデル(入門編)
【Unite 2017 Tokyo】「黒騎士と白の魔王」にみるC#で統一したサーバー/クライアント開発と現実的なUniRx使いこなし術
[KGC 2012] Online Game Server Architecture Case Study Performance and Security
Webアプリを並行開発する際のマイグレーション戦略
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
Javaのログ出力: 道具と考え方
Tackling Complexity
イミュータブルデータモデルの極意
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
世界一わかりやすいClean Architecture
工数把握のすすめ 〜WorkTimeプラグインの使い方〜
ストリーム処理を支えるキューイングシステムの選び方
Spring Boot × Vue.jsでSPAを作る
ClickHouse導入事例紹介
ドメイン駆動設計サンプルコードの徹底解説
UnicodeによるXSSと SQLインジェクションの可能性
nioで作ったBufferedWriterに変えたら例外になった
Ad

Viewers also liked (20)

PPTX
日本 Java ユーザーグループ JJUG CCC 2015 Fall by ソラコム 片山
PPTX
Javaにおけるネイティブコード連携の各種手法の紹介
PDF
よくある業務開発の自動化事情 #jjug_ccc #ccc_cd3
PDF
【こっそり始める】Javaプログラマコーディングマイグレーション
PDF
Java8 Stream APIとApache SparkとAsakusa Frameworkの類似点・相違点
PDF
プログラム初心者がWebサービスをリリースして運営するまで
PDF
Real world machine learning with Java for Fumankaitori.com
PPT
デバッガのしくみ(JDI)を学んでみよう
PPTX
Java8移行から始めた技術的負債との戦い(jjug ccc 2015 fall)
PDF
マイクロサービスアーキテクチャ - アーキテクチャ設計の歴史を背景に
PDF
タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-
PDF
Unified JVM Logging
PPTX
Project Jigsaw #kanjava
PDF
Spring Framework 5.0による Reactive Web Application #JavaDayTokyo
PDF
Arachne Unweaved (JP)
PDF
VMの歩む道。 Dalvik、ART、そしてJava VM
PDF
Jjugccc2017spring-postgres-ccc_m1
PPTX
Kotlin is charming; The reasons Java engineers should start Kotlin.
PDF
Java8移行は怖くない~エンタープライズ案件でのJava8移行事例~
PPTX
U-NEXT学生インターン、過激なJavaの学び方と過激な要求
日本 Java ユーザーグループ JJUG CCC 2015 Fall by ソラコム 片山
Javaにおけるネイティブコード連携の各種手法の紹介
よくある業務開発の自動化事情 #jjug_ccc #ccc_cd3
【こっそり始める】Javaプログラマコーディングマイグレーション
Java8 Stream APIとApache SparkとAsakusa Frameworkの類似点・相違点
プログラム初心者がWebサービスをリリースして運営するまで
Real world machine learning with Java for Fumankaitori.com
デバッガのしくみ(JDI)を学んでみよう
Java8移行から始めた技術的負債との戦い(jjug ccc 2015 fall)
マイクロサービスアーキテクチャ - アーキテクチャ設計の歴史を背景に
タイムマシン採用:明日のエンタープライズJavaの世界を予想する -Java EE7/クラウド/Docker/etc.-
Unified JVM Logging
Project Jigsaw #kanjava
Spring Framework 5.0による Reactive Web Application #JavaDayTokyo
Arachne Unweaved (JP)
VMの歩む道。 Dalvik、ART、そしてJava VM
Jjugccc2017spring-postgres-ccc_m1
Kotlin is charming; The reasons Java engineers should start Kotlin.
Java8移行は怖くない~エンタープライズ案件でのJava8移行事例~
U-NEXT学生インターン、過激なJavaの学び方と過激な要求
Ad

Similar to Reactive Webアプリケーション - そしてSpring 5へ #jjug_ccc #ccc_ef3 (20)

PDF
Reactive Systems と Back Pressure
PDF
SpringOne Platform 2016 報告会「A Lite Rx API for the JVM」/ 井口 貝 @ SmartNews, Inc.
PDF
Typesafe Reactive Platformで作るReactive System
PPTX
Reactive extensions
PDF
Why Reactive Matters #ScalaMatsuri
PDF
Typesafe Reactive Platformで作るReactive System入門
PDF
なぜリアクティブは重要か #ScalaMatsuri
PDF
Reactive android
PPTX
Reactive Programming
PDF
SpringOne 2016 報告 Reactive APIの設計・実装・使用
PDF
Reactive Extensionsはじめました
PDF
Reactive Extensions v2.0
PDF
Akkaの並行性
PDF
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
PPTX
Spring I/O 2019 報告 Spring Frameworkのロードマップと5.2の新機能
PDF
Reactive cocoaをかじってみた。
PPTX
ReactiveUI を使った表計算っぽいWPFアプリケーションで Reactiveプログラミング の練習をした話
PDF
IntelliJ IDEAとKotlinで作るSpring 5アプリケーション
PPTX
Reactive
PDF
FRP - Functional Reactive Programming
Reactive Systems と Back Pressure
SpringOne Platform 2016 報告会「A Lite Rx API for the JVM」/ 井口 貝 @ SmartNews, Inc.
Typesafe Reactive Platformで作るReactive System
Reactive extensions
Why Reactive Matters #ScalaMatsuri
Typesafe Reactive Platformで作るReactive System入門
なぜリアクティブは重要か #ScalaMatsuri
Reactive android
Reactive Programming
SpringOne 2016 報告 Reactive APIの設計・実装・使用
Reactive Extensionsはじめました
Reactive Extensions v2.0
Akkaの並行性
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Spring I/O 2019 報告 Spring Frameworkのロードマップと5.2の新機能
Reactive cocoaをかじってみた。
ReactiveUI を使った表計算っぽいWPFアプリケーションで Reactiveプログラミング の練習をした話
IntelliJ IDEAとKotlinで作るSpring 5アプリケーション
Reactive
FRP - Functional Reactive Programming

More from Toshiaki Maki (20)

PDF
From Spring Boot 2.2 to Spring Boot 2.3 #jsug
PDF
Concourse x Spinnaker #concourse_tokyo
PDF
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1t
PDF
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
PDF
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1
PDF
Spring Boot Actuator 2.0 & Micrometer
PDF
Open Service Broker APIとKubernetes Service Catalog #k8sjp
PDF
Spring Cloud Function & Project riff #jsug
PDF
Introduction to Spring WebFlux #jsug #sf_a1
PDF
BOSH / CF Deployment in modern ways #cf_tokyo
PDF
Why PCF is the best platform for Spring Boot
PDF
Zipkin Components #zipkin_jp
PPTX
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
PDF
実例で学ぶ、明日から使えるSpring Boot Tips #jsug
PDF
Spring ❤️ Kotlin #jjug
PDF
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
PDF
Managing your Docker image continuously with Concourse CI
PDF
Data Microservices with Spring Cloud Stream, Task, and Data Flow #jsug #spri...
PDF
Short Lived Tasks in Cloud Foundry #cfdtokyo
PDF
今すぐ始めるCloud Foundry #hackt #hackt_k
From Spring Boot 2.2 to Spring Boot 2.3 #jsug
Concourse x Spinnaker #concourse_tokyo
Serverless with Spring Cloud Function, Knative and riff #SpringOneTour #s1t
決済システムの内製化への旅 - SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1
Spring Boot Actuator 2.0 & Micrometer #jjug_ccc #ccc_a1
Spring Boot Actuator 2.0 & Micrometer
Open Service Broker APIとKubernetes Service Catalog #k8sjp
Spring Cloud Function & Project riff #jsug
Introduction to Spring WebFlux #jsug #sf_a1
BOSH / CF Deployment in modern ways #cf_tokyo
Why PCF is the best platform for Spring Boot
Zipkin Components #zipkin_jp
マイクロサービスに必要な技術要素はすべてSpring Cloudにある #DO07
実例で学ぶ、明日から使えるSpring Boot Tips #jsug
Spring ❤️ Kotlin #jjug
Event Driven Microservices with Spring Cloud Stream #jjug_ccc #ccc_ab3
Managing your Docker image continuously with Concourse CI
Data Microservices with Spring Cloud Stream, Task, and Data Flow #jsug #spri...
Short Lived Tasks in Cloud Foundry #cfdtokyo
今すぐ始めるCloud Foundry #hackt #hackt_k

Reactive Webアプリケーション - そしてSpring 5へ #jjug_ccc #ccc_ef3