Red Hat Training

A Red Hat training course is available for Red Hat JBoss Web Server

13.2. イベントシステム

永続化層で特定のイベントに対応しなければならない場合、Hibernate3 の イベント アーキテクチャを使うこともできます。さらにイベントシステムはインターセプタと一緒に使うか、またはインターセプタの代わりとして使うこともできます。
Session インターフェースのメソッドはすべて、1個のイベントと相関します。例えば LoadEventFlushEvent などがあります。定義済みのイベント型の完全一覧については、XML 設定ファイルの DTD や org.hibernate.event パッケージを調べてください。リクエストがこれらのメソッドの1つから作られるとき、Hibernate の Session は適切なイベントを生成し、そのイベント型に設定されたイベントリスナに渡します。追加設定なしで、これらのリスナはそのメソッドと同じ処理を実装します。とはいえ、リスナインターフェースの一つを自由にカスタム実装できます (つまり、 LoadEvent は登録された LoadEventListener インターフェースの実装により処理されます)。その場合、その実装には Session から作られたどのような load() リクエストをも処理する責任があります。
リスナは事実上シングルトンであると見なせます。つまり、リスナはリクエスト間で共有されるため、インスタンス変数として状態を保持するべきではありません。
カスタムリスナは処理したいイベントについて適切なインターフェースを実装するべきです。便利な基底クラスのうちの一つを継承してもよいです (または Hibernate がデフォルトで使用するイベントリスナを継承してもよいです。すばらしいことに、この目的のために非 final として宣言されています)。カスタムリスナは Configuration オブジェクトを使ってプログラムから登録するか、Hibernate の XML 設定ファイルで指定できます。プロパティファイルで宣言的に設定する方法はサポートされていません。ここで、カスタムロードイベントリスナの例を示します:
public class MyLoadListener implements LoadEventListener {
    // this is the single method defined by the LoadEventListener interface
    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
            throws HibernateException {
        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
            throw new MySecurityException("Unauthorized access");
        }
    }
}
デフォルトリスナ以外のリスナを使うには、 Hibernate への設定も必要です:
<hibernate-configuration>
    <session-factory>
        ...
        <event type="load">
            <listener class="com.eg.MyLoadListener"/>
            <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
        </event>
    </session-factory>
</hibernate-configuration>
代わりに、プログラムで登録する方法もあります:
Configuration cfg = new Configuration();
LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
cfg.getEventListeners().setLoadEventListeners(stack);
リスナを宣言的に登録するとインスタンスを共有できません。複数の <listener/> 要素で同じクラス名が使われると、それぞれの参照はそのクラスの別インスタンスを指すことになります。リスナ型の間でリスナインスタンスを共有する必要があれば、プログラムで登録する方法を採らなければなりません。
なぜインターフェースを実装して、特化した型を設定時に指定するのでしょうか?リスナの実装に、複数のイベントリスナインターフェースを実装できるからです。登録時に追加で型を指定することで、カスタムリスナの on/off を設定時に簡単に切り替えられます。