Sun ONE Application Server 7 Web アプリケーション開発者ガイド |
サーブレットの使用法このmoduleでは、Sun ONE Application Server 上で行われるアプリケーション対話の制御に有効なサーブレット (標準のサーブレットを含む) の作成方法について説明します。また、このmoduleでは標準を拡張するための Sun ONE Application Server の機能についても説明します。
このmoduleには次の節があります。
サーブレットについて
サーブレットはアプレットと同様に再利用可能な Java アプリケーションです。ただし、サーブレットは Web ブラウザ上ではなく、アプリケーションサーバーまたは Web サーバー上で動作します。
Sun ONE Application Server がサポートしているサーブレットは、Java サーブレット仕様バージョン 2.3 に基づいています。関連するすべての仕様書へは install_dir/docs/index.htm からアクセス可能です。install_dir は、Sun ONE Application Server がインストールされているディレクトリです。
サーブレットはアプリケーションのプレゼンテーションロジックに使われます。サーブレットは、フォーム入力処理、EJB にカプセル化されているビジネスロジックのコンポーネントの起動、JSP を使った Web ページ出力のフォーマットなど、アプリケーションのセントラルディスパッチャとして機能します。サーブレットはユーザーからの要求に応じてコンテンツを生成し、ユーザー対話から次のユーザー対話に続くアプリケーションフローを制御します。
サーブレットの基本的な特徴は次のとおりです。
- サーブレットは、Sun ONE Application Server のサーブレットエンジンによって実行時に作成され、管理される
- サーブレットは、request オブジェクトにカプセル化されている入力データを処理する
- サーブレットは、 response オブジェクトにカプセル化されているクエリデータに応答する
- サーブレットは EJB コンポーネントを呼び出してビジネスロジック機能を実行する
- サーブレットは JSP を呼び出してページレイアウト機能を実行する
- サーブレットは拡張可能であり、Sun ONE Application Server とともに提供される API を使って機能を追加する
- サーブレットは対話中のユーザーセッション情報の持続性を提供する
- サーブレットは、アプリケーションの一部にすることも、複数のアプリケーションで使えるように分離してアプリケーションサーバー上に置くこともできる
- サーブレットはサーバーの動作中に動的に再読み込みされる
- サーブレットは、URL でアドレスを指定できる。アプリケーションのページ上のボタンがサーブレットを指している場合がある
- サーブレットはほかのサーブレットを呼び出すこともできる
サーブレットのデータフロー
ユーザーが「送信」ボタンをクリックすると、表示ページに入力された情報がサーブレットに送信されます。サーブレットは受信データを処理し、EJB などのビジネスロジックコンポーネントに基づいてコンテンツを生成することにより、応答を編成します。コンテンツが作成されると、サーブレットは通常、そのコンテンツを JSP に転送して応答ページを作成します。応答はクライアントに返送され、次のユーザー対話を設定します。
次の図に、サーブレットとの間でやり取りされる情報のフローを示します。
- サーブレットがクライアントの要求を処理する
- サーブレットがコンテンツを生成する
- サーブレットが応答を作成し、
それをクライアントに返送する
または
そのタスクを JSP にディスパッチする
サーブレットはほかの要求を処理できるようにメモリーに残ります。
   サーブレットのデータフロー
サーブレットの種類
サーブレットには主に次の 2 種類があります。
- 汎用サーブレット
- HTTP サーブレット
これらのサーブレットはそれぞれ、リソースの初期化や割り当て解除を行うコンストラクタメソッド init() とデストラクタメソッド destroy() を実装しています。
すべてのサーブレットが、サーブレットに対する要求を処理する service() メソッドを実装する必要があります。汎用サーブレットの場合は、サービスメソッドをオーバーライドして要求処理用のルーチンを用意します。HTTP サーブレットには、使用中の HTTP 転送メソッドに基づいてサーブレット内の別のメソッドに自動的に要求を転送するサービスメソッドがあります。したがって、HTTP サーブレットの場合は doPost() をオーバーライドして POST 要求を処理し、doGet() をオーバーライドして GET 要求を処理します。
サーブレットの作成
サーブレットを作成するには、次の手順を実行します。
- サーブレットをアプリケーションに組み込むように設計します。つまり、サーブレットに汎用的な方法でアクセスされた場合、サーブレットからアプリケーションデータにアクセスできないように設計します。
- GenericServlet または HttpServlet を拡張するクラスを作成し、要求を処理する適切なメソッドをオーバーライドします。
- Sun ONE Application Server 管理インタフェースを使って、Web アプリケーションの配備記述子を作成します。詳細については、「Web モジュールの構築と配備」を参照してください。
この節の残りの部分では次のトピックについて説明します。
クラス宣言の作成
サーブレットを作成するには、基本的な入出力サポートと javax.servlet パッケージを持つ共有 Java クラスを記述します。このクラスは、GenericServlet または HttpServlet を拡張する必要があります。Sun ONE Application Server サーブレットは HTTP 環境に存在するので、HttpServlet の拡張をお勧めします。サーブレットがパッケージに含まれる場合は、クラスローダーがそのサーブレットを正しく配置できるようにパッケージ名も宣言する必要があります。
次のヘッダーの例は、myServlet という HTTP サーブレットの宣言を示しています。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class myServlet extends HttpServlet {
...servlet methods...
}メソッドのオーバーライド
次に、1 つまたは複数のメソッドをオーバーライドして、意図したタスクを実行するための指示をサーブレットに与えます。サーブレットによるすべての処理は、要求ごとに、サービスメソッド (汎用サーブレットの service() メソッドまたは HTTP サーブレットの doOperation() メソッドのどれか) で行われます。このメソッドは受信要求を受け取り、与えられた指示に従って要求を処理し、出力を適切に送信します。同じように、このサーブレットのほかのメソッドも作成できます。
ビジネスロジックには、トランザクションを実行するためのデータベースアクセスや EJB コンポーネントへの要求送信を含めることができます。
初期化メソッドのオーバーライド
カウンタなどのサーブレットインスタンスの生存期間にわたって使用するリソースを初期化したり割り当てたりするには、クラスを初期化する init() をオーバーライドします。init() メソッドは、サーブレットがインスタンス化されてから要求を受け入れるまでの間に実行されます。詳細については、サーブレットの API 仕様書を参照してください。
注 範囲を設定するために、すべての init() メソッドで super.init(ServletConfig) を呼び出す必要があります。これにより、このサーブレットの設定オブジェクトをほかのサーブレットメソッドでも使用できるようになります。この呼び出しを省略すると、サーブレットの呼び出し時に「500 SC_INTERNAL_SERVER_ERROR」がブラウザに表示されます。
注 初期化中に、フィルタなどの Web アプリケーションのコンポーネントが ServletException をスローすると、この Web アプリケーションは起動しません。つまり、Web アプリケーションの一部が実行されると、Web アプリケーション全体が実行されるということです。セキュリティコンポーネントに障害が発生した場合、Web アプリケーションは実行されないことが重要です。
次の init() メソッドの例では、thisMany という共有整数変数を作成することによってカウンタを初期化します。
public class myServlet extends HttpServlet {
int thisMany;
public void init (ServletConfig config) throws ServletException
{
super.init(config);
thisMany = 0;
}
}これで、ほかのサーブレットメソッドがこの変数にアクセスできるようになります。
破棄メソッドのオーバーライド
ログメッセージを書き込んだり、サーブレットの生存期間内に使用されていたリソースを解放したりするには、クラスのデストラクタ destroy() をオーバーライドします。リソースの再利用やガベージコレクションを行うためには、リソースを適切に終了し、参照を解除する必要があります。destroy() メソッドは、サーブレット自体がメモリーの割り当てから解放される直前に実行されます。詳細については、サーブレットの API 仕様書を参照してください。
destroy() メソッドでは、たとえば上記の「初期化メソッドのオーバーライド」の例に基づいて、次のようなログメッセージを書き込むことができます。
out.println("myServlet was accessed " + thisMany " times.¥n");
Service、Get、および Post メソッドのオーバーライド
要求が発生すると、Sun ONE Application Server は受信データをサーブレットエンジンに渡して要求を処理します。要求にはフォームデータ、cookie、セッション情報、URL での名前 - 値のペアなどが含まれています。これらは、要求オブジェクトと呼ばれる HttpServletRequest 型のオブジェクトによって処理されます。クライアントのメタデータは、応答オブジェクトと呼ばれる HttpServletResponse 型のオブジェクトとしてカプセル化されます。サーブレットエンジンは、サーブレットの service() メソッドのパラメータとして両方のオブジェクトを渡します。
HTTP サーブレット内のデフォルトの service() メソッドは、HTTP 転送メソッド (POST、GET など) に基づいて要求をほかのメソッドに転送します。たとえば、HTTP POST 要求は doPost() メソッドに転送され、HTTP GET 要求は doGet() メソッドに転送されます。これにより、サーブレットは転送メソッドに応じてさまざまな要求データ処理を実行できます。要求の転送は service() で行われるため、一般的に HTTP サーブレットの service() をオーバーライドする必要はありません。その代わり、予想される要求型に従って doGet() や doPost() をオーバーライドします。
HTTP サーブレットでの自動転送は、HTTP 転送メソッドを備えている request.getMethod() の呼び出しに基づいています。Sun ONE Application Server では、サーブレットがデータを参照する前に、要求データが名前 - 値のリストに処理されています。このため、HTTP サーブレットの service() メソッドをオーバーライドしても機能は失われません。ただし、これによって前処理された要求データに依存することになるため、サーブレットの移植性は低下します。
要求に対応するために必要なタスクを実行するには、汎用サーブレットの場合は service() メソッドをオーバーライドし、HTTP サーブレットの場合は doGet() メソッドや doPost() メソッドをオーバーライドします。多くの場合、EJB コンポーネントにアクセスしてビジネストランザクションを実行し、要求オブジェクトまたは JDBC ResultSet のオブジェクト内で必要な情報を照合したあと、新たに作成されたコンテンツを JSP に渡してコンテンツのフォーマットとクライアントへの配信を行います。
フォームを伴う多くのオペレーションで GET または POST オペレーションが使われるため、ほとんどのサーブレットについて doGet() または doPost() をオーバーライドします。次の例のように、両方のメソッドを実装して両方の入力タイプに備えたり、要求オブジェクトを中央処理メソッドに渡したりできます。
public void doGet (HttpServletRequest request,
HttpServletResponse response}
throws ServletException, IOException {
doPost(request, response);
}HTTP サーブレットの各要求のトラフィックはすべて、適切な doOperation() メソッドで処理されます。メソッドには、セッション管理、ユーザー認証、EJB コンポーネントや JSP のディスパッチ、および Sun ONE Application Server 機能へのアクセスなどがあります。
サーブレットが RequestDispatcher メソッドの include() または forward() を呼び出す場合は、要求情報が HTTP の POST や GET として転送されなくなるので注意してください。つまり、サーブレットが doPost() をオーバーライドする場合、呼び出し側のサーブレットが HTTP GET 経由でデータを受け取ると、ほかのサーブレットがこのメソッドを呼び出しても何も処理されません。このため、上記の例のように可能性のあるすべての入力タイプのルーチンを実装してください。RequestDispatcher メソッドは常に、service() を呼び出します。
詳細については、「プログラムによるサーブレットの呼び出し」を参照してください。
注 デフォルトでは、Web コネクタは受信データを名前 - 値のペアに変換するため、アップロードされるファイルやイメージなど任意のバイナリデータが問題になることがあります。このような種類のデータを適切に処理し、要求オブジェクト内に正しくパッケージ化するように、Web コネクタをプログラムできます。
パラメータのアクセスとデータの保存
受信データは要求オブジェクトにカプセル化されます。HTTP サーブレットの場合、要求オブジェクト型は HttpServletRequest です。汎用サーブレットの場合、要求オブジェクト型は ServletRequest です。要求オブジェクトは、属性と呼ばれるユーザー独自の要求値を含む、すべての要求パラメータを持っています。
受信要求のすべてのパラメータにアクセスするには、getParameter() メソッドを使います。次に例を示します。
String username = request.getParameter("username");
要求オブジェクト内の値の設定および取得を行うには、それぞれ setAttribute() と getAttribute() を使います。次に例を示します。
request.setAttribute("favoriteDwarf", "Dwalin");
上記の例は、データを JSP に転送する方法を示しています。これは、JSP に暗黙的 Bean としての要求オブジェクトへのアクセス権があるためです。
セッションとセキュリティの処理
Web サーバーまたはアプリケーションサーバーから見ると、Web アプリケーションは関連のないサーバーヒットの連続です。数秒前に対話したばかりでも、ユーザーがそのサイトにアクセスしたことがあるかどうかの自動認識は行われません。セッションは、アプリケーションの状態を記憶することによってユーザーとの複数の対話を関連付けます。クライアントは各対話時に cookie を使って自己を特定します。また、cookie のないブラウザの場合は、URL にセッション識別子を入れることによって自己を特定します。
セッションオブジェクトは、表形式データ、アプリケーションの現在の状態についての情報、現在のユーザーについての情報などのオブジェクトを格納できます。セッションに関連付けられたオブジェクトは、同じセッションを使うほかのコンポーネントから使用できます。
詳細については、「ユーザーセッションの作成と管理」を参照してください。
ログインに成功したら、標準オブジェクト内でユーザーの識別情報を確立するようにサーブレットに指示する必要があります。この標準オブジェクトはセッションオブジェクトと呼ばれ、ユーザーのログイン名や保存の必要がある補足情報など、現在のセッションに関する情報を保持しています。アプリケーションコンポーネントはセッションオブジェクトに対してクエリを実行し、ユーザー認証を取得できます。
アプリケーションでユーザーセッションを安全に行う方法については、「Web アプリケーションのセキュリティ」を参照してください。
ビジネスロジックコンポーネントのアクセス
Sun ONE Application Server のプログラミングモデルでは、データベーストランザクション、ディレクトリトランザクション、複雑な計算などのビジネスロジックを EJB コンポーネントに実装します。request オブジェクトの参照は、指定されたタスクを実行するための EJB パラメータとして渡すことができます。
データベーストランザクションからの結果を JDBC ResultSet オブジェクトに格納し、フォーマットとクライアントへの配信を行うためにコンポーネントにオブジェクト参照を渡します。また、request.setAttribute() メソッドを使って要求オブジェクトの結果を格納したり、session.setAttribute() メソッドを使ってセッションに格納したりできます。要求オブジェクトに格納されるオブジェクトは、要求が有効であるかぎり有効です。つまり、個別のサーブレットスレッドだけに有効です。セッションに格納されるオブジェクトは、セッションが持続している間は存続します。
次の例は、ShoppingCart という EJB コンポーネントにアクセスするサーブレットを示しています。サーブレットは、カートのリモートインタフェースをインポートしてからユーザーのセッション ID をカートに割り当てることによって、カートのハンドルを作成します。カートはユーザーのセッション内に格納されます。
import cart.ShoppingCart;
// ユーザーのセッションおよびショッピングカートを取得します。
HttpSession session = request.getSession(true);
ShoppingCart cart =
(ShoppingCart)session.getAttribute(session.getId());
// ユーザーがカートを持っていない場合は新規に作成します。
if (cart == null) {
String jndiNm = "java:comp/env/ejb/ShoppingCart";
javax.naming.Context initCtx = null;
Object home = null;
try {
initCtx = new javax.naming.InitialContext(env);
java.util.Properties props = null;
home = initCtx.lookup(jndiNm);
cart = ((IShoppingCartHome) home).create();
session.setValue(session.getId(),cart);
}
catch (Exception ex) {
.....
.....
}
}Java Naming Directory Interface (JNDI) を使ってサーブレットから EJB コンポーネントにアクセスし、EJB コンポーネントへのハンドルまたはプロキシを確立します。次に、正規オブジェクトとして EJB を参照します。このとき、オーバーヘッドは Bean のコンテナによって管理されます。
次の例は、ショッピングカートのプロキシを検索する JNDI を示しています。
String jndiNm = "java:comp/env/ejb/ShoppingCart";
javax.naming.Context initCtx;
Object home;
try
{
initCtx = new javax.naming.InitialContext(env);
}
catch (Exception ex)
{
return null;
}
try
{
java.util.Properties props = null;
home = initCtx.lookup(jndiNm);
}
catch(javax.naming.NameNotFoundException e)
{
return null;
}
catch(javax.naming.NamingException e)
{
return null;
}
try
{
IShoppingCart cart = ((IShoppingCartHome) home).create();
}
catch (...) {...}EJB コンポーネントの詳細については、『Sun ONE Application Server Enterprise JavaBeans 開発者ガイド』を参照してください。
注 JNDI 内のその他のエンタープライズリソース名との衝突や移植性の問題を回避するため、Sun ONE Application Server アプリケーション内のすべての名前を、文字列 java:comp/env で始める必要があります。
スレッドの処理
デフォルトでは、サーブレットはスレッドセーフになっていません。通常、1 つのサーブレットインスタンス内のメソッドは、使用可能なメモリーの範囲内で同時に何回も実行されます。メソッドの実行は、それぞれ別のスレッドで行われますが、サーブレットエンジンにはサーブレットのコピーが 1 つしか存在しません。
これによってシステムリソースの使用率が向上しますが、Java でのメモリー管理方法に起因する危険性があります。サーブレットクラスに属する変数は参照によって渡されるため、別のスレッドが同じメモリー空間を上書きしてしまうことがあります。サーブレット (またはサーブレット内のブロック) をスレッドセーフにするには、次のどちらかを行います。
- public synchronized void method() (メソッド全体) または synchronized(this) {...} (ブロックのみ) のように、すべてのインスタンス変数に対する書き込みアクセスの同期をとります。同期をとることによって応答時間が大幅に遅くなるため、ブロックだけの同期をとるか、またはサーブレット内のブロックで同期が不要かを確認してください。
たとえば、次のサーブレットには doGet() 内にスレッドセーフのブロックがあり、さらに mySafeMethod() というスレッドセーフのメソッドがあります。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class myServlet extends HttpServlet {
public void doGet (HttpServletRequest request,
HttpServletResponse response}
throws ServletException, IOException {
//前処理
synchronized (this) {
//このブロック内のコードはスレッドセーフです。
}
//前処理
}
public synchronized int mySafeMethod (HttpServletRequest request)
{
// このメソッド内で行われる処理はすべてスレッドセーフです。
}
}
- SingleThreadModel クラスを使ってシングルスレッドのサーブレットを作成します。シングルスレッドのサーブレットを Sun ONE Application Server に配備すると、サーブレットエンジンは受信要求に備えてサーブレットインスタンスをプールします。つまり、同じサーブレットの複数のコピーをメモリー内に用意します。このプール内のサーブレットインスタンスの数は、Sun ONE Application Server 固有の Web アプリケーション配備記述子の singleThreadedServletPoolSize プロパティを設定することによって変更できます。Sun ONE Application Server の Web アプリケーション配備記述子の詳細については、「Web モジュールの構築と配備」を参照してください。シングルスレッドのサーブレットは、新規要求を処理するためにインスタンスの空きを待つ必要があるため、その負荷によって動作が遅くなります。ただし、ロードバランスが有効な分散アプリケーションでは、ビジーでないプロセスに負荷が自動的に移行するため、これが問題になることはありません。
たとえば、次のサーブレットは完全なシングルスレッドです。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class myServlet extends HttpServlet
implements SingleThreadModel {
servlet methods...
}クライアントへの結果の配信
ユーザーとの対話の最終作業はクライアントに応答ページを配信することです。応答ページは次の 2 つの方法で配信できます。
サーブレット応答ページの作成
出力ストリームに書き込むことによって、サーブレット内で出力ページを生成します。出力タイプによって推奨方法は異なります。
すべての出力を開始する前に、setContentType() を使って出力の MIME タイプを必ず指定します。次に例を示します。
response.setContentType("text/html");
単純な HTML などのテキスト出力の場合は、PrintWriter オブジェクトを作成してから println を使って書き込みます。次に例を示します。
PrintWriter output = response.getWriter();
output.println("Hello, World¥n");バイナリ出力の場合は、ServletOutputStream オブジェクトを作成してから print() を使って書き込むことによって、出力ストリームに直接書き込みます。次に例を示します。
ServletOutputStream output = response.getOutputStream();
output.print(binary_data);JSP 応答ページの作成
サーブレットは次の 2 つの方法で JSP を呼び出せます。
- RequestDispatcher インタフェースの include() メソッドは、JSP を呼び出し、JSP が返されてから対話処理を続行します。include() メソッドは、特定のサーブレット内で複数回呼び出すことができます。
次の例は、include() を使った JSP を示しています。
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher("JSP_URI");
dispatcher.include(request, response);
... //処理の継続
- RequestDispatcher インタフェースの forward() メソッドは対話の制御を JSP に渡します。forward() を呼び出すと、サーブレットは現在の対話の出力と無関係になります。つまり、特定のサーブレットで forward() メソッドを呼び出すことができるのは 1 回だけです。
注 PrintWriter オブジェクトまたは ServletOutputStream オブジェクトをすでに定義している場合は、forward() メソッドを使うことができないので注意してください。
次の例は、forward() を使った JSP を示しています。
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher("JSP_URI");
dispatcher.forward(request, response);
JSP の詳細については、「JavaServer Pages の使用法」を参照してください。
サーブレットの呼び出し
サーブレットを呼び出すには、URL を使ってアプリケーションページから直接アドレスを指定するか、すでに実行しているサーブレットからプログラムで呼び出します。次の節を参照してください。
URL によるサーブレットの呼び出し
アプリケーションの HTML または JSP ページ内にリンクとして埋め込まれた URL を使って、サーブレットを呼び出すことができます。URL の形式は次のとおりです。
http://server:port/context_root/servlet/servlet_name?name=value
次の表は、URL の各セクションについて説明しています。左の列は URL 要素、右の列は各 URL 要素の説明です。
この例では、 sun はホスト名、MortPages はコンテキストルート、calcMortgage はサーブレット名です。
http://www.sun.com/MortPages/servlet/calcMortgage?rate=8.0&per=360&bal=180000
プログラムによるサーブレットの呼び出し
まず、URI を指定して、呼び出すサーブレットを指定します。通常、これは現在のアプリケーションに対応する相対パスになります。たとえば、サーブレットが OfficeFrontEnd という名前のコンテキストルートを持つアプリケーションの一部である場合、ブラウザから ShowSupplies という名前のサーブレットへの URL は次のようになります。
http://server:port/OfficeApp/OfficeFrontEnd/servlet/ShowSupplies?name=value
プログラムによってほかのサーブレットからこのサーブレットを呼び出すには次の 2 つの方法があります。
- ほかのサーブレットの出力を含めるには、RequestDispatcher インタフェースから include() メソッドを使います。このメソッドは、URI で サーブレットを呼び出し、サーブレットが返されてから対話処理を続行します。include() メソッドは、特定のサーブレット内で複数回呼び出すことができます。
次に例を示します。
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher("/ShowSupplies");
dispatcher.include(request, response);
- ほかのサーブレットに対話制御を渡すには、RequestDispatcher インタフェースの forward() メソッドを使用します。このとき、サーブレットの URI をパラメータとして指定します。
注 要求を転送した場合、forward() を呼び出すと、元のサーブレットは現在の対話の出力とは無関係になるので注意してください。つまり、特定のサーブレットで forward() を呼び出せるのは 1 回だけです。
次の例は、include() を使った JSP を示しています。
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher("/ShowSupplies");
dispatcher.forward(request, response);サーブレットの出力
ServletContext.log メッセージはサーバーログに送信されます。
デフォルトでは、サーブレットの出力 System.out および System.err はサーバーログに送られます。また、起動時にサーバーログメッセージが System.err 出力にエコーされます。またデフォルトでは、System.err 出力用の Windows コンソールはありません。これらのデフォルト設定は次の方法で変更できます。
管理インタフェースの使用
次の手順に従って管理インタフェースを使用します。
- 管理インタフェースのサーバーインスタンスページで「ログ」タブをクリックします。
- 次のチェックボックスをオンまたはオフにします。
「標準出力をイベントログとして記録」 - trueにすると、System.out 出力がサーバーログに送られます。
「標準エラー出力をイベントログとして記録」 - trueにすると、System.err 出力がサーバーログに送られます。
「標準エラー出力にエコー」 - trueにすると、サーバーログメッセージが System.err 出力にエコーされます。
「コンソールを作成」 - System.err 出力用の Windows コンソールを作成します。
- 「保存」ボタンをクリックします。
- サーバーインスタンスページに移動し、「変更の適用」ボタンを選択します。
詳細については、『Sun ONE Application Server 管理者ガイド』を参照してください。
server.xml ファイルの編集
server.xml ファイルを次のように編集し、サーバーを再起動します。
<log-service log-stdout=false
log-stderr=false
echo-log-messages-to-stderr=false
create-console=true />create-console は Windows 専用の属性です。server.xml の詳細については、『Sun ONE Application Server 管理者用設定ファイルリファレンス』を参照してください。
サーブレットの結果のキャッシュ
Sun ONE Application Server は、サーブレット、JSP、または任意の URL パターン を呼び出した結果をキャッシュしておくことができ、その後に同じサーブレット、JSP、または URL パターンを呼び出す際、すばやく呼び出すことができます。Sun ONE Application Server は、要求の結果を一定の期間キャッシュします。そのため、ほかのデータ呼び出しがあったときに、Sun ONE Application Server は、再びオペレーションを実行する代わりに、キャッシュしておいたデータを返します。たとえば、5 分ごとに更新される株式相場をサーブレットが返す場合、キャッシュが 300 秒後に期限切れになるように設定します。
結果をキャッシュするかどうかや、キャッシュする方法は、結果に含まれているデータによって異なります。たとえば、クイズの投稿の結果は、サーブレットへの入力が毎回異なるため、キャッシュしても意味がありません。ただし、1 時間ごとに更新される、クイズの結果から収集した人口統計データを示す、高度なレポートをキャッシュすることは考えられます。
sun-web.xml ファイル内で特定のフィールドを編集することによって、Sun ONE Application Server の Web アプリケーションで応答キャッシュを処理する方法を定義できます。このように、有効な Sun ONE Application Server 機能を利用した標準サーブレットをプログラムで作成できます。
JSP のキャッシュの詳細については、「JSP キャッシュ」を参照してください。
注 静的ファイルコンテンツのキャッシュについては、『Sun ONE Application Server 管理者用設定ファイルリファレンス』で説明されている nsfc.conf ファイルを参照してください。
この節の残りの部分では次のトピックについて説明します。
キャッシュ機能
Sun ONE Application Server 7 には、次の Web アプリケーション応答キャッシュ機能があります。
- キャッシュはサーブレットの名前または URI に基づいて設定可能
- URI に基づくキャッシュの場合は、クエリ文字列にユーザーが指定したパラメータは URI に含まれる。たとえば、/garden/catalog?category=roses からの応答と /garden/catalog?category=lilies からの応答とは異なる。これらの応答は異なるキーでキャッシュに格納される
- キャッシュサイズ、エントリのタイムアウトなどのキャッシュ動作は設定可能
- エントリのタイムアウトは、エントリの作成または更新が行われた時点から測定される。個々のキャッシュ割り当てのタイムアウト値は、cache-mapping サブ要素を timeout に指定することによって上書き可能
- キャッシュヘルパークラスを作成することで、キャッシュ条件をプログラムで判断できる。たとえば、バックエンドのデータソースの最終更新時刻に関する情報だけをサーブレットが持っている場合は、最終更新のタイムスタンプをデータソースから取得し、応答をキャッシュするかどうかをそのタイムスタンプに基づいて判断するヘルパークラスを作成できる。「CacheHelper インタフェース」を参照
- キャッシュキージェネレータクラスを作成することで、キャッシュキーの生成条件をプログラムで判断できる。「CacheKeyGenerator インタフェース」を参照
- キャッシュキー要素で指定された、ASCII 以外の要求パラメータ値はすべて、URL でエンコードされる必要がある。キャッシュのサブシステムは、要求のクエリ文字列にある生パラメータ値に一致するよう試みる
- ただし、クラスが新たに更新されるとキャッシュされる内容にも影響を与えるため、クラスの動的配備や動的再読み込みを行う際、Web コンテナはキャッシュをクリアする
- HttpServletRequest 要求の次の属性は公開される
デフォルトのキャッシュ設定
サーブレットや JSP のキャッシュ機能を有効にし、特別な設定を行わない場合、デフォルトのキャッシュの設定は次のようになります。
- デフォルトのキャッシュタイムアウトは 30 秒
- HTTP GET メソッドだけをキャッシュに使用できる
- cookie やセッションを使った HTTP 要求があると、キャッシュ機能は自動的に無効になる
- Pragma:、Cache-control:、および Vary: の各ヘッダーは特に考慮されない
- デフォルトキーはサーブレットパス (pathInfo とクエリ文字列を除いたもの) で構成される
- 最近使用されたキャッシュエントリのリストが保持されているため、最大キャッシュサイズを超えた場合に古いキャッシュエントリを削除できる
- サーブレットのパスとキーのフィールド値 (指定されている場合) を連結してキーが生成される
キャッシュの例
sun-web.xml ファイルの cache 要素の例を次に示します。
<cache max-capacity="8192" timeout="60">
<cache-helper name="myHelper" class-name="MyCacheHelper"/>
<cache-mapping>
<servlet-name>myservlet</servlet name
<timeout name="timefield">120</timeout>
<http-method>GET</http-method>
<http-method>POST</http-method>
</cache-mapping>
<cache-mapping>
<url-pattern> /catalog/* </url-pattern>
<!-- 最もよく売れているカテゴリをキャッシュします。
-- 特定のパラメータが存在するときだけ、このリソースへの応答をキャッシュします。
-- catalog パラメータが 'lilies' または 'roses' の場合だけキャッシュし、
-- ほかの値のときはキャッシュしません。つまり、
-- /orchard/catalog?best&category='lilies'
-- /orchard/catalog?best&category='roses'
-- の結果はキャッシュしますが、次の結果はキャッシュしません。
-- /orchard/catalog?best&category='wild'
-->
<constraint-field name='best' scope='request.parameter'/>
<constraint-field name='category' scope='request.parameter'>
<value> roses </value>
<value> lilies </value>
</constraint-field>
<!-- 特定のフィールドの範囲を指定します。ただし、このフィールドはすべての要求に
-- 含まれていなくてもかまいません。>
<constraint-field name='SKUnum' scope='request.parameter'>
<value match-expr='in-range'> 1000 - 2000 </value>
</constraint-field>
<!-- 特定の値以外のいずれかの値と category が一致する場合だけキャッシュします。>
<constraint-field name="category" scope="request.parameter>
<value match-expr="equals" cache-on-match-failure="true">bogus</value>
</constraint-field>
</cache-mapping>
<cache-mapping>
<servlet-name> InfoServlet </servlet name>
<cache-helper-ref>myHelper</cache-helper-ref>
</cache-mapping>
</cache>sun-web.xml のキャッシュ設定の詳細については、「キャッシュに関する要素」を参照してください。
CacheHelper インタフェース
CacheHelper インタフェースは次のとおりです。
package com.sun.appserv.web.cache;
import java.util.Map
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
/** CacheHelper インタフェースはユーザーによる拡張が可能なインタフェースであり、
* 応答をキャッシュするかどうかと、キー生成をカスタマイズできます。
*/
public interface CacheHelper {
// 要求の属性の名前
public static final String ATTR_CACHE_MAPPED_SERVLET_NAME =
"com.sun.appserv.web.cachedServletName";
public static final String ATTR_CACHE_MAPPED_URL_PATTERN =
"com.sun.appserv.web.cachedURLPattern";
public static final int TIMEOUT_VALUE_NOT_SET = -2;
/** ヘルパーを初期化します。
* @引数 context は、このヘルパーが属している Web アプリケーションです。
* @例外 Exception は、起動エラーが発生した場合にスローされます。
*/
public void init(ServletContext context, Map props) throws Exception;
/** getCacheKey: この要求をキャッシュするためのキーを生成します。
* @引数 request は、受信した<code>HttpServletRequest</code> オブジェクトです。
* @この要求されたキャッシュ可能なリソースについて生成したキーを返します。
*/
public String getCacheKey(HttpServletRequest request);
/** isCacheable: 特定の要求に対する応答がキャッシュ可能かどうかを調べます。
* @引数 request は、受信した<code>HttpServletRequest</code> オブジェクトです。
* @応答がキャッシュ可能な場合は <code>true</code> を返し、
* キャッシュ不可能な場合は <code>false</code> を返します。
*/
public boolean isCacheable(HttpServletRequest request);
/** isRefreshNeeded: 特定の要求に対する応答について、更新が必要かどうかを調べます。
* @引数 request は、受信した<code>HttpServletRequest</code> オブジェクトです。
* @応答の更新が必要な場合は <code>true</code> を返し、
* この要求の結果を更新する必要がない場合は <code>false</code> を返します。
*/
public boolean isRefreshNeeded(HttpServletRequest request);
/** キャッシュされた応答のタイムアウトを取得します。
* @引数 request は、受信した<code>HttpServletRequest</code> オブジェクトです。
* @キャッシュされた応答のタイムアウトを秒単位で返します。
* 値 -1 は、この応答が無期限に有効であることを示し、
* 値 -2 は、ヘルパーでタイムアウトを調べられないことを示します (コンテナがデフォルトの
* タイムアウトを割り当てる)。
*/
public int getTimeout(HttpServletRequest request);
/**
* ヘルパーの使用を中止します。
* @例外 Exception は、エラーが発生した場合にスローされます。
*/
public void destroy() throws Exception;
}CacheKeyGenerator インタフェース
Web アプリケーションは、デフォルトで組み込まれている CacheHelper 実装を使ってキー生成をカスタマイズできます。サーブレットまたは JSP 内のアプリケーションコンポーネントは、ServletContext 内の属性としてカスタム CacheKeyGenerator 実装を設定できます。
コンテキスト属性の名前は、sun-web.xml 配備記述子の default-helper 要素内の cacheKeyGeneratorAttrName プロパティ値 value として設定できます。詳細については、「default-helper」を参照してください。
CacheKeyGenerator インタフェースは次のとおりです。
package com.sun.appserv.web.cache;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
/** CacheKeyGenerator: この要求をキャッシュするためのキーを生成するヘルパー
* インタフェース
*
* CacheKeyGenerator を実装する ServletContext 属性の名前は、
* sun-web.xml 内の default-helper プロパティを使って設定できます。
* <default-helper>
* <property
* name="cacheKeyGeneratorAttrName"
* value="com.acme.web.MyCacheKeyGenerator" />
* </default-helper>
*
* キャッシュエンジンは、指定された属性をサーブレットコンテキスト内で検索します。
* 検索結果は CacheKeyGenerator インタフェースの実装であることが必要です。
*/
public interface CacheKeyGenerator {
/** getCacheKey: この応答をキャッシュするためのキーを生成します。
* @引数 context は、この Web アプリケーションのコンテキストです。
* @引数 request は、受信した<code>HttpServletRequest</code>
* オブジェクトです。
* @キャッシュエントリにアクセスするためのキー文字列を返します。
* null が返された場合は、デフォルトのキーが使用されます。
*/
public String getCacheKey(ServletContext context,
HttpServletRequest request);
}サーブレットエンジンについて
サーブレットは Sun ONE Application Server のサーブレットエンジン内に存在し、このエンジンによって管理されます。このサーブレットエンジンは、サーブレットのすべてのメタファンクションを処理する内部オブジェクトです。このメタファンクションには、インスタンス化、初期化、破棄、ほかのコンポーネントからのアクセス、設定管理などがあります。
サーブレットのインスタンス化と削除
サーブレットエンジンは、サーブレットをインスタンス化したあと、その init() メソッドを実行して必要な初期化を行います。カウンタの初期化など、サーブレットの生存期間にわたって使用される関数の初期化を実行するには、このメソッドをオーバーライドします。
サーブレットがサービスから削除されると、サーバーエンジンは、最後のタスクを実行し、リソースの割り当てを解除できるように、サーブレット内の destroy() メソッドを呼び出します。ログメッセージを書き込んだり、ガベージコレクション時に検出されない残留コネクションを削除したりするには、このメソッドをオーバーライドします。
要求処理
要求が発生すると、Sun ONE Application Server は受信データをサーブレットエンジンに渡します。サーブレットエンジンは、要求の入力データ (フォームデータ、cookie、セッション情報、URL の名前 - 値のペアなど) を処理して HttpServletRequest 要求オブジェクトタイプにします。
サーブレットエンジンは HttpServletResponse 応答オブジェクトタイプも作成します。その後、両方のオブジェクトをパラメータとしてサーブレットの service() メソッドに渡します。
HTTP サーブレット内のデフォルトの service() メソッドは、HTTP 転送メソッド (POST や GET など) に基づいて要求をほかのメソッドに転送します。たとえば、HTTP POST 要求は doPost() メソッドに転送され、HTTP GET 要求は doGet() メソッドに転送されます。これにより、サーブレットは使用中の転送メソッドに応じて要求データをさまざまな方法で処理できます。要求の転送はサービスメソッドによって行われるため、一般的に HTTP サーブレットの service() をオーバーライドする必要はありません。その代わり、予想される要求タイプに従って doGet() や doPost() などをオーバーライドします。
要求に応答するタスクを実行するには、service() メソッド (汎用サーブレット) または doGet() メソッドや doPost() メソッド (HTTP サーブレット) をオーバーライドします。多くの場合、EJB コンポーネントにアクセスしてビジネストランザクションを実行し、要求オブジェクトまたは JDBC ResultSet オブジェクト内で情報を照合したあと、新たに作成されたコンテンツを JSP に渡してコンテンツのフォーマットとユーザーへの配信を行います。
サーブレットエンジンのリソースの割り当て
デフォルトでは、サーブレットエンジンは新規要求ごとにスレッドを作成します。この場合、要求ごとにメモリー内でサーブレットの新規コピーをインスタンス化するよりもリソースに与える影響は小さくなります。各スレッドが同じメモリー空間で動作し、サーブレットオブジェクトの変数が互いを上書きする場合があるので、スレッド問題の発生を避ける必要があります。
サーブレットが特にシングルスレッドとして作成されている場合、サーブレットエンジンは受信要求に使用するサーブレットインスタンスをプールします。すべてのインスタンスが使用中であるときに要求を受信すると、インスタンスが使用可能になるまで要求はキューに入れられます。プールするインスタンスの数は、sun-web.xml ファイル内の sun-web-app 要素の singleThreadedServletPoolSize プロパティで設定できます。
sun-web.xml ファイルの詳細については、「Web モジュールの構築と配備」を参照してください。スレッド問題の詳細については、「スレッドの処理」を参照してください。