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]をチェックすることができます。