休止状態のインターセプター

1概要

この議論では、http://hibernate.org[Hibernate’s]によって抽象化されたリレーショナルマッピングの実装の中で操作を傍受するためのさまざまな方法に注目します。

2 Hibernateインターセプターの定義

Hibernate InterceptorはHibernate内の特定のイベントに反応することを可能にするインターフェースです。

これらのインターセプターはコールバックとして登録され、Hibernateのセッションとアプリケーション間の通信リンクを提供します。このようなコールバックを使用すると、アプリケーションは__save、update、deleteなどのHibernateのコア操作を傍受できます

インターセプターを定義する方法は2つあります。

  1. org.hibernate.Interceptor インターフェースの実装

  2. org.hibernate.EmptyInterceptor クラスを拡張する

2.1. Interceptor インターフェースの実装

  • org.hibernate.Interceptor を実装するには、約14の付随するメソッドを実装する必要があります** 。これらのメソッドには、 onLoad、onSave、onDelete、findDirty、 などがあります。

Interceptorインターフェースを実装するクラスが直列化可能であることを確認することも重要です( implements java.io.Serializable )。

典型的な例は次のようになります。

public class CustomInterceptorImpl implements Interceptor, Serializable {

    @Override
    public boolean onLoad(Object entity, Serializable id,
      Object[]state, String[]propertyNames, Type[]types)
      throws CallbackException {
       //...
        return false;
    }

   //...

    @Override
    public String onPrepareStatement(String sql) {
       //...
        return sql;
    }

}

特別な要件がない場合は、 EmptyInterceptor ** クラスを拡張し、必要なメソッドをオーバーライドすることを強くお勧めします。

2.2. EmptyInterceptor を拡張する

org.hibernate.EmptyInterceptor クラスを拡張すると、インターセプターを定義するより簡単な方法が提供されます。傍受したい操作に関連するメソッドをオーバーライドするだけです。

たとえば、 CustomInterceptor を次のように定義できます。

public class CustomInterceptor extends EmptyInterceptor {
}

そして、実行前にデータ保存操作を傍受する必要がある場合は、 onSave メソッドをオーバーライドする必要があります。

@Override
public boolean onSave(Object entity, Serializable id,
  Object[]state, String[]propertyNames, Type[]types) {

    if (entity instanceof User) {
        logger.info(((User) entity).toString());
    }
    return super.onSave(entity, id, state, propertyNames, types);
}

User の場合、この実装はどのように単純にエンティティを表示するのかに注意してください。

true または false の値を返すことは可能ですが、 super.onSave() を呼び出して onSave イベントの伝播を許可することをお勧めします。

  • もう1つのユースケースは、データベースインタラクションのための監査証跡を提供することです** エンティティがいつ変更されるかを知るために onFlushDirty() メソッドを使うことができます。

User オブジェクトについては、 User 型のエンティティが変更されるたびに、その lastModified dateプロパティを更新することを決定できます。

これは次のようにして達成できます。

@Override
public boolean onFlushDirty(Object entity, Serializable id,
  Object[]currentState, Object[]previousState,
  String[]propertyNames, Type[]types) {

    if (entity instanceof User) {
        ((User) entity).setLastModified(new Date());
        logger.info(((User) entity).toString());
    }
    return super.onFlushDirty(entity, id, currentState,
      previousState, propertyNames, types);
}

delete load (オブジェクトの初期化)などの他のイベントは、対応する onDelete メソッドと onLoad メソッドをそれぞれ実装することで傍受できます。

3 __インターセプターの登録

Hibernateインターセプターは Session スコープまたは__SessionFactoryスコープとして登録できます。

3.1. セッションスコープのインターセプター

Session スコープのインターセプターは特定のセッションにリンクされています。セッションが次のように定義または開かれるときに作成されます。

public static Session getSessionWithInterceptor(Interceptor interceptor)
  throws IOException {
    return getSessionFactory().withOptions()
      .interceptor(interceptor).openSession();
}

上記では、インターセプターを特定の休止状態セッションに明示的に登録しました。

3.2. SessionFactory スコープ Interceptor

SessionFactory- スコープスコープインターセプターは__SessionFactoryを構築する前に登録されます。

ServiceRegistry serviceRegistry = configureServiceRegistry();
SessionFactory sessionFactory = getSessionFactoryBuilder(serviceRegistry)
  .applyInterceptor(new CustomInterceptor())
  .build();

__SessionFactory - __スコープスコープインターセプターはすべてのセッションに適用されることに注意することが重要です。したがって、このインターセプタは異なるセッションで同時に使用されるため、セッション固有の状態を格納しないように注意する必要があります。

セッション固有の動作の場合は、前に示したように、異なるインターセプタとのセッションを明示的に開くことをお勧めします。

SessionFactory スコープのインターセプターの場合、当然スレッドセーフであることを確認する必要があります。これは、プロパティファイルでセッションコンテキストを指定することで実現できます。

hibernate.current__session__context__class=org.hibernate.context.internal.ThreadLocalSessionContext

または、これをXML設定ファイルに追加してください。

<property name="hibernate.current__session__context__class">
    org.hibernate.context.internal.ThreadLocalSessionContext
</property>

また、直列化可能性を確保するために、 SessionFactory スコープのインターセプターは、 Serializable インターフェースの readResolve メソッドを実装する必要があります。

4結論

Hibernateインターセプターを Session スコープまたは SessionFactory スコープとして定義および登録する方法を見ました。どちらの場合でも、特に直列化可能セッションが必要な場合は、インターセプターが直列化可能であることを確認する必要があります。

インターセプターの他の代替手段には、Hibernate EventsやJPA Callbacksがあります。

そして、いつものように、完全なhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/hibernate5[source code over Github]をチェックすることができます。