コネクション・プール管理のサーブレットを使った事例(シングルトンのポイント)
|
|
コネクション・プール管理のサーブレットを使った事例(シングルトンのポイント)
コネクション・プールを管理するHans Bergsten氏のサーブレットを紹介しよう。このサーブレットはアプリケーションのための他のサーブレット達と共にコンテナに配備される。但しこのサーブレットは他のサーブレットにDB接続をサービスするためのもので、他のサーブレットに共有されるので、そのインスタンスがひとつしか存在しないいわゆるシングルトン(Singleton)である。
Singletonのクラスの構造は一般に次のようになる。
static private Singleton
instance;
// 単一のインスタンス(最初はnull) static private int
clients = 0; // Javaでは初期設定なしでも基本データ型は初期値
//
となるが、明示的記述を推奨する /** * 単一のインスタンスを返すメソッド。 * 最初にこのメソッドが呼ばれたときにはインスタンスを生成する * * @return Singletonこの単一のインスタンス */ static synchronized
public Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); } clients++;
return instance; } |
GetInstanceメソッドが呼ばれると、Singletonクラスは自分自身のインスタンスを保持するstatic変数(クラス変数)であるinstanceをチェックし、自分のインスタンスがあればそれを返し、無ければインスタンスを生成し、これをinstanceという変数に代入してこれを返す。Bergsten氏の文献にあるソースコードもこれに準じていることがお分かりであろう。クラス変数はこのクラスの複数のオブジェクト間で共有される唯一の変数(複製を持たない変数)である。int型のclientという変数もクラス変数である。static宣言された変数やメソッドに対しては、クラスローダは複数のインスタンスを生成したとしてもこれらのインスタンスとは独立したエリアに配備し、複製が作られることを防止する。
サーブレット環境におけるSingletonクラスの取扱いには注意すべき点がひとつある。それは、クラスローダに対する注意である。殆どのサーブレット・エンジンの場合にサーブレットに変更が加えられた場合に自動的に変更済みのサーブレットをコンテナにロードする機能(自動再ロード機能)を持つ。シングルトン(つまりヘルパー)のクラスであってもこの機能により複数のインスタンスが生成される危険性がある。この問題を避けるためには、
1. この機能を無効に設定する
2. このサーブレットは自動再ロードの対象となるディレクトリに置かず、別のディレクトリとし、CLASSPATH宣言で配備させる。
という対策が必要である。支障がなければ1.の手段を使うべきである。
たとえばTomcatのconfというディレクトリにあるserver.xmlという設定ファイルには以下のような記述がある。
<Context path="/examples"
docBase="webapps/examples"
crossContext="false"
debug="0"
reloadable="true" >
</Context> |
このreloadable要素を”false”にすると、このアプリケーションでの自動再ロードは無効となる。
さてDBコネクション・プールを管理するDBConnectionManagerというシングルトンのクラスをRational社のUMLツールであるRose 2000eを使ってクラス図を作成してみると次のようになろう。
DBConnectionManagerクラスはinstanceというクラス変数を介して自分自身のオブジェクトを生成(Create)している。DBConnectionPoolはDBConnectionManagerのインナークラスである。DBConnectionManagerは複数のDBConnectionPoolの生成と管理を行う。
これをもう少し漫画的に表現すれば下図のようになる。
ConnectionManagerは複数のConnectionPoolを管理する。例えばOracle用のPoolだとかmySQL用のPoolだとか複数のDBリソースに対応させるときに有用である。また一般ユーザ用と管理用や特定のアクセス権のユーザ用に分離するのも有効であろう。各Poolはインスタンス化の際に最大コネクション数が与えられる。アプリケーションのサーブレットがコネクションを取得/開放するときは、CoonectionPoolから直接取得/開放することが出来るが、ConnectionManager経由で窓口を一本化して取得/開放することをお勧めする。