ライフサイクルイベント

MongoDB マッピングフレームワークには、特別な Bean を ApplicationContext に登録することでアプリケーションが応答できるいくつかの org.springframework.context.ApplicationEvent イベントが含まれています。Spring の ApplicationContext イベントインフラストラクチャに基づいているため、Spring Integration などの他の製品はこれらのイベントを簡単に受信できます。これは、これらのイベントが Spring ベースのアプリケーションでよく知られているイベントメカニズムであるためです。

エンティティのライフサイクルイベントはコストがかかる場合があり、大規模な結果セットを読み込むときにパフォーマンスプロファイルの変化に気づく場合があります。テンプレート API ではライフサイクルイベントを無効にすることができます。

オブジェクトが変換プロセス (ドメインオブジェクトを org.bson.Document に変換する) を通過する前にインターセプトするには、onBeforeConvert メソッドをオーバーライドする AbstractMongoEventListener のサブクラスを登録します。イベントがディスパッチされると、リスナーが呼び出され、コンバーターに入る前にドメインオブジェクトが渡されます。次の例は、そのメソッドを示しています。

public class BeforeConvertListener extends AbstractMongoEventListener<Person> {
  @Override
  public void onBeforeConvert(BeforeConvertEvent<Person> event) {
    ... does some auditing manipulation, set timestamps, whatever ...
  }
}

オブジェクトがデータベースに入る前にそれをインターセプトするには、onBeforeSave メソッドをオーバーライドする AbstractMongoEventListener (Javadoc) のサブクラスを登録します。イベントがディスパッチされると、リスナーが呼び出され、ドメインオブジェクトと変換された com.mongodb.Document が渡されます。次の例は、そのメソッドを示しています。

public class BeforeSaveListener extends AbstractMongoEventListener<Person> {
  @Override
  public void onBeforeSave(BeforeSaveEvent<Person> event) {
    … change values, delete them, whatever …
  }
}

Spring ApplicationContext でこれらの Bean を宣言すると、イベントが送出されるたびにそれらの Bean が呼び出されます。

AbstractMappingEventListener でのコールバック:
  • onBeforeConvert: オブジェクトが MongoConverter によって Document に変換される前に、MongoTemplate insertinsertListsave 操作で呼び出されます。

  • onBeforeSaveDocument をデータベースに挿入または保存する前に、 MongoTemplate insertinsertListsave 操作で呼び出されます。

  • onAfterSaveDocument をデータベースに挿入または保存した後、 MongoTemplate insertinsertListsave 操作で呼び出されます。

  • onAfterLoadDocument がデータベースから取得された後、MongoTemplate findfindAndRemovefindOnegetCollection メソッドで呼び出されます。

  • onAfterConvert: データベースから Document が取得され、POJO に変換された後、MongoTemplate findfindAndRemovefindOnegetCollection メソッドで呼び出されます。

ライフサイクルイベントは、ルートレベルの型に対してのみ発行されます。ドキュメントルート内のプロパティとして使用される複合型は、@DBRef のアノテーションが付けられたドキュメント参照でない限り、イベント発行の対象になりません。
ライフサイクルイベントは ApplicationEventMulticaster に依存します。SimpleApplicationEventMulticaster の場合、TaskExecutor を使用して構成できるため、イベントが処理されるときの保証はありません。

エンティティコールバック

Spring Data インフラストラクチャは、特定のメソッドが呼び出される前後にエンティティを変更するためのフックを提供します。いわゆる EntityCallback インスタンスは、コールバック形式のエンティティをチェックし、潜在的に変更する便利な方法を提供します。
 EntityCallback は、特化した ApplicationListener に非常によく似ています。一部の Spring Data モジュールは、特定のエンティティの変更を許可するストア固有のイベント(BeforeSaveEvent など)を公開します。不変の型を操作する場合など、これらのイベントは問題を引き起こす可能性があります。また、イベント発行は ApplicationEventMulticaster に依存しています。非同期 TaskExecutor を使用して構成すると、イベント処理をスレッドに分岐できるため、予測不能な結果を招く可能性があります。

エンティティコールバックは、同期ポイントとリアクティブ API の両方を統合ポイントに提供して、処理チェーン内の明確に定義されたチェックポイントでの順序実行を保証し、潜在的に変更されたエンティティまたはリアクティブラッパー型を返します。

エンティティコールバックは通常、API 型によって分離されます。この分離は、同期 API が同期エンティティコールバックのみを考慮し、リアクティブ実装がリアクティブエンティティコールバックのみを考慮することを意味します。

Entity Callback API は Spring Data Commons 2.2 で導入されました。エンティティの変更を適用するための推奨される方法です。既存のストア固有の ApplicationEvents は、登録されている可能性のある EntityCallback インスタンスを呼び出すに公開されます。

エンティティコールバックの実装

EntityCallback は、ジェネリクス型引数を介してドメイン型に直接関連付けられます。通常、各 Spring Data モジュールには、エンティティのライフサイクルをカバーする一連の定義済み EntityCallback インターフェースが付属しています。

EntityCallback の構造
@FunctionalInterface
public interface BeforeSaveCallback<T> extends EntityCallback<T> {

	/**
	 * Entity callback method invoked before a domain object is saved.
	 * Can return either the same or a modified instance.
	 *
	 * @return the domain object to be persisted.
	 */
	(1)
	T onBeforeSave(T entity, (2)
		String collection); (3)
}
1 エンティティが保存される前に呼び出される BeforeSaveCallback 固有のメソッド。潜在的に変更されたインスタンスを返します。
2 永続化する直前のエンティティ。
3 エンティティが永続化されるコレクションなどのストア固有の引数の数。
リアクティブ EntityCallback の構造
@FunctionalInterface
public interface ReactiveBeforeSaveCallback<T> extends EntityCallback<T> {

	/**
	 * Entity callback method invoked on subscription, before a domain object is saved.
	 * The returned Publisher can emit either the same or a modified instance.
	 *
	 * @return Publisher emitting the domain object to be persisted.
	 */
	(1)
	Publisher<T> onBeforeSave(T entity, (2)
		String collection); (3)
}
1 エンティティが保存される前に、サブスクリプションで呼び出される BeforeSaveCallback 固有のメソッド。潜在的に変更されたインスタンスを発行します。
2 永続化する直前のエンティティ。
3 エンティティが永続化されるコレクションなどのストア固有の引数の数。
オプションのエンティティコールバックパラメーターは、実装 Spring Data モジュールによって定義され、EntityCallback.callback() の呼び出しサイトから推測されます。

次の例に示すように、アプリケーションのニーズに合ったインターフェースを実装します。

例 BeforeSaveCallback
class DefaultingEntityCallback implements BeforeSaveCallback<Person>, Ordered {      (2)

	@Override
	public Object onBeforeSave(Person entity, String collection) {                   (1)

		if(collection == "user") {
		    return // ...
		}

		return // ...
	}

	@Override
	public int getOrder() {
		return 100;                                                                  (2)
	}
}
1 要件に応じたコールバックの実装。
2 同じドメイン型のエンティティコールバックが複数存在する場合、エンティティコールバックを潜在的にオーダーします。優先順位は最低です。

エンティティコールバックの登録

EntityCallback Bean は、ApplicationContext に登録されている場合に、ストア固有の実装によってピックアップされます。ほとんどのテンプレート API はすでに ApplicationContextAware を実装しているため、ApplicationContext にアクセスできます。

次の例は、有効なエンティティコールバック登録のコレクションを説明しています。

EntityCallback Bean 登録の例
@Order(1)                                                           (1)
@Component
class First implements BeforeSaveCallback<Person> {

	@Override
	public Person onBeforeSave(Person person) {
		return // ...
	}
}

@Component
class DefaultingEntityCallback implements BeforeSaveCallback<Person>,
                                                           Ordered { (2)

	@Override
	public Object onBeforeSave(Person entity, String collection) {
		// ...
	}

	@Override
	public int getOrder() {
		return 100;                                                  (2)
	}
}

@Configuration
public class EntityCallbackConfiguration {

    @Bean
    BeforeSaveCallback<Person> unorderedLambdaReceiverCallback() {   (3)
        return (BeforeSaveCallback<Person>) it -> // ...
    }
}

@Component
class UserCallbacks implements BeforeConvertCallback<User>,
                                        BeforeSaveCallback<User> {   (4)

	@Override
	public Person onBeforeConvert(User user) {
		return // ...
	}

	@Override
	public Person onBeforeSave(User user) {
		return // ...
	}
}
1BeforeSaveCallback は @Order アノテーションからオーダーを受け取ります。
2BeforeSaveCallback は、Ordered インターフェース実装を介してオーダーを受け取ります。
3 ラムダ式を使用した BeforeSaveCallback。デフォルトでは順不同で、最後に呼び出されます。ラムダ式によって実装されたコールバックはタイピング情報を公開しないため、割り当て不可能なエンティティでこれらを呼び出すと、コールバックのスループットに影響することに注意してください。class または enum を使用して、コールバック Bean の型フィルタリングを有効にします。
4 単一の実装クラスに複数のエンティティコールバックインターフェースを組み合わせます。

特定の EntityCallbacks を保存する

Spring Data MongoDB は、監査サポートに EntityCallback API を使用し、次のコールバックに反応します。

表 1: サポートされているエンティティのコールバック
コールバック メソッド 説明 順序

ReactiveBeforeConvertCallback BeforeConvertCallback

onBeforeConvert(T entity, String collection)

ドメインオブジェクトが org.bson.Document に変換される前に呼び出されます。

Ordered.LOWEST_PRECEDENCE

ReactiveAfterConvertCallback AfterConvertCallback

onAfterConvert(T entity, org.bson.Document target, String collection)

ドメインオブジェクトがロードされた後に呼び出されます。
 org.bson.Document からドメインオブジェクトを読み取った後、ドメインオブジェクトを変更できます。

Ordered.LOWEST_PRECEDENCE

ReactiveAuditingEntityCallback AuditingEntityCallback

onBeforeConvert(Object entity, String collection)

作成または変更 された監査可能なエンティティをマークします

100

ReactiveBeforeSaveCallback BeforeSaveCallback

onBeforeSave(T entity, org.bson.Document target, String collection)

ドメインオブジェクトが保存される前に呼び出されます。
マップされたすべてのエンティティ情報を含む Document を永続化するために、ターゲットを変更できます。

Ordered.LOWEST_PRECEDENCE

ReactiveAfterSaveCallback AfterSaveCallback

onAfterSave(T entity, org.bson.Document target, String collection)

ドメインオブジェクトが保存される前に呼び出されます。
ドメインオブジェクトを変更して、保存後に返されるようにすることができます。Document には、マップされたすべてのエンティティ情報が含まれています。

Ordered.LOWEST_PRECEDENCE