ライフサイクルイベント

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

オブジェクトがデータベースに入る前にそれをインターセプトするには、onBeforeSave(…) メソッドをオーバーライドする AbstractCassandraEventListener (Javadoc) のサブクラスを登録します。イベントがディスパッチされると、リスナーが呼び出され、ドメインオブジェクト (Java エンティティ) が渡されます。エンティティライフサイクルイベントはコストがかかる可能性があり、大きな結果セットをロードするときにパフォーマンスプロファイルに変化が見られることがあります。テンプレート API でライフサイクルイベントを無効にすることができます。次の例では、onBeforeSave メソッドを使用しています。

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

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

AbstractCassandraEventListener (Javadoc) には次のコールバックメソッドがあります。

  • onBeforeSave: データベース内の行を挿入または更新する前、ただし Statement を作成した後に、CassandraTemplate.insert(…) および .update(…) 操作で呼び出されます。

  • onAfterSave: データベース内の行の挿入または更新後に、CassandraTemplate … insert(…) および .update(…) 操作で呼び出されます。

  • onBeforeDelete: データベースから行を削除する前に、CassandraTemplate.delete(…) 操作で呼び出されます。

  • onAfterDelete: データベースから行を削除した後、CassandraTemplate.delete(…) 操作で呼び出されます。

  • onAfterLoad: データベースから各行が取得された後、CassandraTemplate.select(…).slice(…).stream(…) メソッドで呼び出されます。

  • onAfterConvert: データベースから取得した行を POJO に変換した後、CassandraTemplate.select(…).slice(…).stream(…) メソッドで呼び出されます。

ライフサイクルイベントは、ルートレベルの型に対してのみ発行されます。集約ルート内のプロパティとして使用される複合型は、イベント発行の対象になりません。

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

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

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

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

ReactiveBeforeConvertCallback BeforeConvertCallback

onBeforeConvert(T entity, CqlIdentifier tableName)

ドメインオブジェクトが Statement に変換される前に呼び出されます。ドメインオブジェクトを更新して、Statement の変更を含めることができます。

Ordered.LOWEST_PRECEDENCE

ReactiveAuditingEntityCallback AuditingEntityCallback

onBeforeConvert(Object entity, CqlIdentifier tableName)

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

100

ReactiveBeforeSaveCallback BeforeSaveCallback

onBeforeSave(T entity, CqlIdentifier tableName, Statement statement)

ドメインオブジェクトが保存される前に呼び出されます。
 Statement の作成後にターゲットオブジェクトを変更できます。提供されたステートメントには、マップされたすべてのエンティティ情報が含まれていますが、ドメインオブジェクトへの変更は Statement には含まれません。

Ordered.LOWEST_PRECEDENCE