https://blogs.oracle.com/arungupta/entry/non_blocking_i_o_using
Servlet 3.0では非同期リクエスト処理が可能ですが、Traditional I/Oしか使えませんでした。そのため、アプリケーションのスケーラビリティに制限が出ることがあります。通常、アプリケーションではwhileループ内で
ServletInputStream
を読んでいます。インバウンドデータがブロックされたり、サーバーの読み取り可能なスピードよりも遅く流れると、サーバースレッドはデータを待ちます。データをpublic class TestServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { ServletInputStream input = request.getInputStream(); byte[] b = new byte[1024]; int len = -1; while ((len = input.read(b)) != -1) { . . . } } }
ServletOutputStream
に書き出す場合でも同じことが起こりえます。This is resolved in Servet 3.1 (JSR 340:Java EE 7の一部としてリリースされる予定です)ではこの問題をイベントリスナー、
ReadListener
とWriteListener
インターフェースを追加することによって解決します。リスナーは、コンテンツがブロッキングなしで読み取り可能、もしくは書き出し可能になった時点で起動されるコールバックメソッドを持ちます。JSR 340: Java Servlet 3.1 Specification
http://jcp.org/en/jsr/detail?id=340
Interface EventListener
http://docs.oracle.com/javase/7/docs/api/java/util/EventListener.html
doGet
を書き換えると、次のようになります。AsyncContext context = request.startAsync(); ServletInputStream input = request.getInputStream(); input.setReadListener(new MyReadListener(input, context));
setXXXListener
メソッドを呼び出すということは、Traditional I/Oではなく、non-blocking I/Oを使うことを意味します。高々1個のReadListener
をServletIntputStream
に登録でき、同様に高々1個のWriteListener
をServletOutputStream
に登録することができます。 ServletInputStream.isReady
とServletInputStream.isFinished
は新しいメソッドで、non-blocking I/O readの状況をチェックできます。ServletOutputStream.canWrite
はデータをブロックせずに書き込めるかどうかを確認する新しいメソッドです。MyReadListener
の実装は次のような感じです。この実装には3個のコールバックメソッドがあります。@Override public void onDataAvailable() { try { StringBuilder sb = new StringBuilder(); int len = -1; byte b[] = new byte[1024]; while (input.isReady() && (len = input.read(b)) != -1) { String data = new String(b, 0, len); System.out.println("--> " + data); } } catch (IOException ex) { Logger.getLogger(MyReadListener.class.getName()).log(Level.SEVERE, null, ex); } } @Override public void onAllDataRead() { System.out.println("onAllDataRead"); context.complete(); } @Override public void onError(Throwable t) { t.printStackTrace(); context.complete(); }
onDataAvailable
コールバック・メソッド:データをブロックせずに読み出すことが可能な場合に呼び出されるonAllDataRead
コールバック・メソッド:現在のリクエストを完全に読み込んだ際に呼び出されるonError
コールバック・メソッド:リクエスト処理中にエラーが発生した場合に呼び出される
context.complete()
はonAllDataRead
もしくはonError
でデータの読み込み完了を通知するために呼び出されることにご注意ください。現在のところ、データの最初のチャンク(塊)をサーブレットの
doGet
もしくはservice
メソッドで読み取る必要がありますが、そのあと、残りのデータはnon-blocking方式でReadListener
を使って読み取ることができます。これにより、すべての読み取りデータはReadListener
でのみ発生することになります。このエントリでご紹介したサンプルはここからダウンロードできます。実行する場合はGlassFish 4.0 build 64以降のものをお使いください。
GlassFish 4.0 build 64JavaOneでのセッション「What's new in Servlet 3.1: An Overview」の動画とセッション資料は以下のリンクからどうぞ。
http://dlc.sun.com.edgesuite.net/glassfish/4.0/promoted/glassfish-4.0-b64.zip
Promoted build
http://dlc.sun.com.edgesuite.net/glassfish/4.0/promoted/
CON6793 - What’s New in Servlet 3.1: An Overview
https://oracleus.activeevents.com/connect/sessionDetail.ww?SESSION_ID=6793
以下は参考資料です。
- Java EE 7 Specification Status
https://wikis.oracle.com/display/GlassFish/PlanForGlassFish4.0#PlanForGlassFish4.0-SpecificationStatus - Servlet Specification Project
http://java.net/projects/servlet-spec/ - JSR Expert Group Discussion Archive
http://java.net/projects/servlet-spec/lists/users/archive - Servlet 3.1 Javadocs
http://java.net/projects/servlet-spec/downloads/download/Early%20Draft%20Review/javax.servlet-api-3.0.99-SNAPSHOT-javadoc.jar
WebLogic Channelの過去記事も参考にどうぞ。
Java Servlet 3.1の新機能――クラウド対応のJava EE 7でどう変わるのか?【Java EEエキスパート・シリーズ】
https://blogs.oracle.com/weblogic_channel/entry/javaee_c116
0 件のコメント:
コメントを投稿