Spring MVCストリーミングおよびSSEリクエスト処理
1. 前書き
この簡単なチュートリアルでは、Spring MVC 5.x.xでいくつかの非同期およびストリーミングオブジェクトを使用する方法を示します。
具体的には、次の3つの主要なクラスを確認します。
-
ResponseBodyEmitter
-
SseEmitter
-
StreamingResponseBody
また、JavaScriptクライアントを使用してそれらを操作する方法についても説明します。
2. ResponseBodyEmitter
ResponseBodyEmitterは非同期応答を処理します。
また、これはいくつかのサブクラスの親を表します。そのうちの1つを以下で詳しく見ていきます。
2.1. サーバ側
ResponseBodyEmitterを専用の非同期スレッドと一緒に使用し、ResponseEntityでラップすることをお勧めします(emitterを直接挿入できます)。
@Controller
public class ResponseBodyEmitterController {
private ExecutorService executor
= Executors.newCachedThreadPool();
@GetMapping("/rbe")
public ResponseEntity handleRbe() {
ResponseBodyEmitter emitter = new ResponseBodyEmitter();
executor(() -> {
try {
emitter.send(
"/rbe" + " @ " + new Date(), MediaType.TEXT_PLAIN);
emitter.complete();
} catch (Exception ex) {
emitter.completeWithError(ex);
}
});
return new ResponseEntity(emitter, HttpStatus.OK);
}
}
したがって、上記の例では、we can sidestep needing to use CompleteableFutures、より複雑な非同期promise、または@Asyncアノテーションの使用。
代わりに、非同期エンティティを宣言し、ExecutorService.によって提供される新しいThreadでラップするだけです。
2.2. クライアント側
クライアント側で使用する場合は、単純なXHRメソッドを使用して、通常のAJAX操作と同じようにAPIエンドポイントを呼び出すことができます。
var xhr = function(url) {
return new Promise(function(resolve, reject) {
var xmhr = new XMLHttpRequest();
//...
xmhr.open("GET", url, true);
xmhr.send();
//...
});
};
xhr('http://localhost:8080/javamvcasync/rbe')
.then(function(success){ //... });
3. SseEmitter
SseEmitter is actually a subclass of ResponseBodyEmitter and provides additional Server-Sent Event (SSE)はすぐに使用できるサポートを提供します。
3.1. サーバ側
それでは、この強力なエンティティを活用するコントローラーの例を簡単に見てみましょう。
@Controller
public class SseEmitterController {
private ExecutorService nonBlockingService = Executors
.newCachedThreadPool();
@GetMapping("/sse")
public SseEmitter handleSse() {
SseEmitter emitter = new SseEmitter();
nonBlockingService.execute(() -> {
try {
emitter.send("/sse" + " @ " + new Date());
// we could send more events
emitter.complete();
} catch (Exception ex) {
emitter.completeWithError(ex);
}
});
return emitter;
}
}
かなり標準的な料金ですが、これと通常のRESTコントローラーとの間にいくつかの違いがあります。
-
まず、SseEmitterを返します
-
また、コア応答情報を独自のThreadでラップします
-
最後に、 emitter.send()を使用して応答情報を送信します
3.2. クライアント側
今回は、継続的に接続されているServer-Sent Eventライブラリを活用できるため、クライアントの動作が少し異なります。
var sse = new EventSource('http://localhost:8080/javamvcasync/sse');
sse.onmessage = function (evt) {
var el = document.getElementById('sse');
el.appendChild(document.createTextNode(evt.data));
el.appendChild(document.createElement('br'));
};
4. StreamingResponseBody
最後に、we can use StreamingResponseBody to write directly to an OutputStream before passing that written information back to the client using a ResponseEntity.
4.1. サーバ側
@Controller
public class StreamingResponseBodyController {
@GetMapping("/srb")
public ResponseEntity handleRbe() {
StreamingResponseBody stream = out -> {
String msg = "/srb" + " @ " + new Date();
out.write(msg.getBytes());
};
return new ResponseEntity(stream, HttpStatus.OK);
}
}
4.2. クライアント側
前と同じように、通常のXHRメソッドを使用して上記のコントローラーにアクセスします。
var xhr = function(url) {
return new Promise(function(resolve, reject) {
var xmhr = new XMLHttpRequest();
//...
xmhr.open("GET", url, true);
xmhr.send();
//...
});
};
xhr('http://localhost:8080/javamvcasync/srb')
.then(function(success){ //... });
次に、これらの例のいくつかの成功した使用法を見てみましょう。
5. すべてをまとめる
サーバーを正常にコンパイルし、上記のクライアントを実行すると(提供されたindex.jspにアクセス)、ブラウザーに次のように表示されます。
そして私たちのターミナルでは次のようになります。
エンドポイントを直接呼び出して、ブラウザにストリーミング応答が表示されるのを確認することもできます。
6. 結論
FutureとCompleteableFutureは、JavaとSpringに強力に追加されたことが証明されていますが、現在、高度に並行するWebアプリケーションの非同期データとストリーミングデータをより適切に処理するためのリソースがいくつかあります。
最後に、完全なコード例over on GitHubを確認してください。