このセクションでは、Web アプリケーションのサーブレットコンポーネントのコードを改善するための具体的な手法について説明します。Web アプリケーションの要素を変更する予定がある場合は、デザインパターンの使用も検討する必要があります。デザインパターンの詳細については、弟 2 章、「デザインパターン」を参照してください。
可能な場合は、クライアントがリクエストするたびに Web アプリケーションがスタティックデータをダイナミックに生成するのではなく、キャッシュするようにしてください。サーブレットを使用して、init
メソッドでスタティックデータをキャッシュすることができます。
サーブレットが web.xml ファイルに登録されており、load-on-startup
要素が 1 に設定されていると、JRun はサーバの起動時に init
メソッドを呼び出します。そうでない場合は、クライアントが最初にサーブレットをリクエストしたときに (最初のみ)、JRun は init
メソッドを呼び出します。
次の例はサーブレットの init
メソッドを示しています。このメソッドは、アプリケーションの web.xml ファイルから初期化パラメータを取得し、サーブレットの doGet
メソッド内で後で使用されるフッターを作成します。
ServletConfig オブジェクトを介して init
メソッドを呼び出すことも、介さずに呼び出すこともできます。ただし、この場合は、初期化パラメータにアクセスしてフッターを作成できるように、ServletConfig を使用してメソッドを呼び出します。
public class InitOverride extends HttpServlet { String name;
String email; String copyright; String footer;
public void init (ServletConfig config) throws ServletException {
super.init(config); name = config.getInitParameter("name"); email = config.getInitParameter("email"); copyright = config.getInitParameter("copyright"); footer = ("<HR><FONT FACE=¥"arial,helvetica,sans-serif¥" SIZE=-2>Copyright " + copyright + ".Brought to you by:<A HREF=¥"mailto:"+ email + "¥">" + name + "</A></FONT>"); }
public void doGet ( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter(); response.setContentType("text/html"); ... out.println(footer); out.println( "</body></html>" ); } }
次の行は、初期化パラメータを含めた web.xml ファイル内のサーブレット定義を示しています。
<servlet>
<servlet-name>InitOverride</servlet-name> <servlet-class>InitOverride</servlet-class> <init-param> <param-name>name</param-name> <param-value>Nick Danger</param-value> </init-param> <init-param> <param-name>email</param-name> <param-value>ndanger@sandstonebuilding.com</param-value> </init-param> <init-param> <param-name>copyright</param-name> <param-value>2000, 2001, 2002</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
ServletContext オブジェクトはオブジェクトを属性として保管します。アプリケーション内のすべてのサーブレットが同じコンテキストにアクセスするため、ハッシュテーブルなどの構造のようなオブジェクトをキャッシュすることによって、アプリケーションの処理負荷を軽減できます。さらに、オブジェクトをサーブレットの init
メソッド内のコンテキストに保管すると、メソッドは 1 回しか実行されません。
サーブレットの init
メソッドを使用してオブジェクトを作成し、ServletContext 内に保管し、ServletContext.getAttribute
への呼び出しを使用してサーブレットの本文内のオブジェクトにアクセスします。データベーステーブルの場合は、ResultSet オブジェクトを属性として保管できません。配列などのオブジェクトとしてデータの要素を変更する必要があります。
次の例では、サーブレットの init
メソッド内で ResultSet オブジェクトを反復処理し、コンテキストの setAttribute
メソッドを使用して ServletContext 内に Hashtable オブジェクトを保管します。サーブレットは doGet
メソッド内で ServletContext を介して Hashtable オブジェクトにアクセスし、リクエストパラメータを使用して適切な出力行を取得します。
public void init () throws ServletException {
... ResultSet rs = stmt.executeQuery(sqlstmt); Hashtable h = new Hashtable(); while (rs.next()) { h.put(rs.getString("ABBR"),rs.getString("LONGNAME")); } getServletContext().setAttribute("statelist", h); ... }
public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
... Hashtable h = (Hashtable) getServletContext(). getAttribute("statelist"); String state = (String) h.get(request.getParameter("state")); out.println(request.getParameter("state") + " is an abbreviation for " + state); ... }
JSP で作業を行う場合は、ServletContext オブジェクトとして暗黙に宣言されている application オブジェクトを使用します。
PrintWriter オブジェクトにデータを送信する際は、次の例のように println
メソッドではなく print
メソッドを使用します。
PrintWriter out = response.getWriter();
//out.println("これは効率のよくない出力です。"); out.print("これは効率のよい出力です。");
Java では、print
メソッドの方が println
メソッドよりも効率のよい出力メソッドです。println
は内部で入力を取り込み、print
に送信します。println
と print
の使用方法の違いは、println
が文字列の最後に改行文字を挿入することです。しかし、クライアントで HTML のソースを表示しないかぎり、出力のレンダリング方法は変わりません。
ステート管理の場合、非表示フィールド、Cookie、および URL リライティングではなく HttpSession オブジェクトを使用します。HttpSession API を使用する際に、JRun はクライアントとサーバ間でセッションデータ自体ではなくセッション ID だけを渡します。これは、セッションオブジェクトの API により実装の詳細が非表示になっているため、他のメソッドよりも使用し易くなっています。
JSP 開発者の場合は、暗黙のセッションオブジェクトを使用します。
HttpSession オブジェクトを使用したステート管理の詳細については、 「セッションの操作」 を参照してください。
ページ全体のロードが終了する前にクライアントにページの一部が表示されるように、定期的にデータをフラッシュします。それによってアプリケーションの全体的なレスポンス速度が速くなるわけではありませんが、ユーザーはページがより速やかに処理されたように感じます。
この手法は、ダウンロードに時間がかかるグラフィックスが多く含まれているセクションや多くの処理が必要なセクションがある場合に有効です。
PrintWriter out = response.getWriter();
out.print(header); out.flush(); //ヘッダーをフラッシュします。 ... out.print("/images/large_graphic.gif"); out.flush(); //本文内の容量の大きいグラフィックをフラッシュします。 ... out.print(footer); out.flush(); //フッターをフラッシュします。
この手法は、暗黙の out オブジェクトとともに JSP ページに使用します。
サーブレットはレスポンスオブジェクトのバッファー内のコンテンツをロードします。バッファーが満杯の場合、サーブレットはクライアントへのソケット接続を作成し、バッファーをフラッシュします。ソケットおよびネットワークトラフィックの数を減らすには、バッファーの容量を大きくします。
サーブレットのレスポンスバッファーのデフォルト値は 4 KB です。レスポンスサイズがこのサイズに到達すると、JRun はバッファーをフラッシュします。次の例のように setBufferSize
メソッドを使用して、バッファーに大きい値を設定し、必要なフラッシュ回数を減らします。
response.setBufferSize(8192);
バッファーのサイズを確認するには、次の例のように getBufferSize
メソッドを使用します。
out.print("バッファーサイズは " + response.getBufferSize() です。);
PrintWriter のバッファーサイズを拡張すると、JRun によるレスポンスデータのフラッシュ回数が減少します。その結果、オープンソケットや接続の数が減少します。
次の例のように ByteArrayOutputStream オブジェクトを使用して PrintWriter のバッファーサイズを大きくします。
...
response.setContentType("text/html"); ByteArrayOutputStream bos = new ByteArrayOutputStream(8192); PrintWriter out = new PrintWriter(bos, true); out.print("<html><head><title>Using BytaArrayOutputStream</title></ head>"); out.print("<body>"); ... out.print( "</body></html>" ); response.setContentLength(bos.size()); bos.writeTo(response.getOutputStream()); ...
ServletContext.log メソッドへの呼び出しにより、パフォーマンスが低下する場合があります。可能な範囲内でこのメソッドへの呼び出しを制限し、System.out.println への呼び出しを使用します。