利用可能な2つの異なる機能があります。
servlet 3.は、コンテナスレッドとは異なるスレッドでリクエストを処理できます。
サーブレット3.1スレッドの読み取り/書き込みをブロックせずにソケットへの読み取り/書き込みを許可します
インターネットには、サーブレット3.0機能に関する多くの例があります。 Springでとても簡単に使用できます。 DefferedResult
またはCompletableFuture
を返すだけです
しかし、私は春にサーブレット3.1の使用例を見つけることができません。私の知る限り、WriteListener
とReadListener
を登録し、内部でダーティな作業を行う必要があります。しかし、私はそのリスナーの例を見つけることができません。簡単なことではないと思います。
リスナー実装の説明とともに、春のサーブレット3.1機能の例を提供していただけませんか?
いくつかの例を追うのは難しくありません。 IBMから WASdev/sample.javaee7.servlet.nonblocking で見つけました。 SpringまたはSpring Bootで_javax.servlet
_ APIを操作することは、HttpServletRequest
またはHttpServletResponse
を注入するようにSpringに要求することだけです。したがって、簡単な例は次のようになります。
_@SpringBootApplication
@Controller
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@RequestMapping(path = "")
public void writeStream(HttpServletRequest request, HttpServletResponse response) throws IOException {
ServletOutputStream output = response.getOutputStream();
AsyncContext context = request.startAsync();
output.setWriteListener(new WriteListener() {
@Override
public void onWritePossible() throws IOException {
if ( output.isReady() ) {
output.println("WriteListener:onWritePossible() called to send response data on thread : " + Thread.currentThread().getName());
}
context.complete();
}
@Override
public void onError(Throwable t) {
context.complete();
}
});
}
}
_
これは単にWriteListener
を作成し、それを要求出力ストリームに添付して戻ります。派手なものは何もありません。
編集:ポイントは、データをブロックせずに書き込むことができる場合、サーブレットコンテナ(Tomcatなど)がonWritePossible
を呼び出すことです。この詳細については サーブレット3.1を使用した非ブロッキングI/O:Java EE 7(TOTD#188))を使用したスケーラブルなアプリケーション を参照してください。
リスナー(およびライター)には、コンテンツを読み取ることができる場合、またはブロックせずに書き込むことができる場合に呼び出されるコールバックメソッドがあります。
したがって、onWritePossible
は、ブロックせずに_out.println
_を呼び出せる場合にのみ呼び出されます。
SetXXXListenerメソッドを呼び出すと、従来のI/Oの代わりに非ブロックI/Oが使用されます。
多分あなたがしなければならないことは、バイトを書き続けることができるかどうか知るために_output.isReady
_をチェックすることです。ブロックサイズについて、送信者/受信者と何らかの暗黙の合意が必要になるようです。私はそれを使用したことがないのでわかりませんが、Springフレームワークでこれの例を要求すると、それが提供されます。
したがって、onWritePossibleは、out.printlnをブロックせずに呼び出すことができる場合にのみ呼び出されます。 それは正しいように聞こえますが、どのようにして何バイトを書き込むことができるかをどのように理解できますか?これをどのように制御すればよいですか?
編集2:それは私があなたに正確な答えを与えることができない非常に良い質問です。サーバーがメインサーブレットとは別の(非同期)スレッドでコードを実行すると、onWritePossible
が呼び出されると想定します。例からinput.isReady()
またはoutput.isReady()
を確認すると、送信者/受信者がさらに準備ができるまでスレッドがブロックされると思います。これは非同期で行われるため、サーバー自体はブロックされず、他の要求を処理できます。私はこれを使用したことがないので、私は専門家ではありません。
ブロックサイズについて送信者/受信者と何らかの暗黙の合意があると私が言ったとき、それは、受信者が1024バイトブロックを受け入れることができる場合、_output.isReady
_がtrueのときにその量を書き込むことを意味します。ドキュメンテーションを読むことでそれについての知識がなければなりません、それについてのAPIには何もありません。それ以外の場合は1バイトを書き込むことができますが、Oracleの例では1024バイトのブロックを使用しています。 1024バイトブロックは、ストリーミングI/Oのかなり標準的なブロックサイズです。上記の例は、Oracleの例に示されているように、while
ループにバイトを書き込むように拡張する必要があります。それは読者に残された演習です。
プロジェクトリアクターとSpring Webfluxにはbackpressure
の概念があり、これをより注意深く扱うことができます。それは別の質問になるだろうし、私はそれが送信者と受信者をどのように結合するか(またはその逆)については詳しく調べていない。