生命周期事件

Cassandra 映射框架内置了多个 org.springframework.context.ApplicationEvent 事件,您的应用程序可以通过在 ApplicationContext 中注册特殊的 Bean 来响应这些事件。 由于这些事件基于 Spring 的应用上下文事件基础设施,因此其他产品(例如 Spring Integration)可以轻松接收这些事件,因为它们是 Spring 应用程序中广为人知的事件机制。spring-doc.cadn.net.cn

要在对象进入数据库之前拦截它,您可以注册 AbstractCassandraEventListener 的子类并重写 onBeforeSave(…) 方法。 当事件被分发时,您的监听器将被调用并接收域对象(即 Java 实体)。 实体生命周期事件可能开销较大,在加载大型结果集时,您可能会注意到性能特征发生变化。 您可以在 模板 API 上禁用生命周期事件。 以下示例使用了 onBeforeSave 方法:spring-doc.cadn.net.cn

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

在您的 Spring ApplicationContext 中声明这些 Bean 将导致它们在事件被分发时被调用。spring-doc.cadn.net.cn

  • onBeforeSave:在 CassandraTemplate.insert(…).update(…) 操作中调用,时机是在数据库中插入或更新行之前,但在创建 Statement 之后。spring-doc.cadn.net.cn

  • onAfterSave:在 CassandraTemplate…insert(…).update(…) 操作中,向数据库插入或更新一行数据之后调用。spring-doc.cadn.net.cn

  • onBeforeDelete:在 CassandraTemplate.delete(…) 操作中,从数据库删除行之前调用。spring-doc.cadn.net.cn

  • onAfterDelete:在 CassandraTemplate.delete(…) 操作中,从数据库删除行之后调用。spring-doc.cadn.net.cn

  • onAfterLoad:在从数据库中检索每一行数据后,由 CassandraTemplate.select(…).slice(…).stream(…) 方法调用。spring-doc.cadn.net.cn

  • onAfterConvert:在从数据库检索到一行数据并将其转换为 POJO 之后,由 CassandraTemplate.select(…).slice(…).stream(…) 方法调用。spring-doc.cadn.net.cn

生命周期事件仅针对根级别类型发出。 作为聚合根内部属性使用的复杂类型不会触发事件发布。

实体回调

Spring Data 基础设施提供了在调用某些方法之前和之后修改实体的钩子。 这些所谓的EntityCallback实例提供了一种便捷的方式,以回调风格检查并可能修改实体。
An EntityCallback看起来非常像一个专门的ApplicationListener. 一些 Spring Data 模块会发布特定存储的事件(例如BeforeSaveEvent) 允许修改给定的实体。在某些情况下,例如处理不可变类型时,这些事件可能会引发问题。 此外,事件发布依赖于ApplicationEventMulticaster. 如果使用异步方式配置该功能TaskExecutor它可能导致不可预测的结果,因为事件处理可以分叉到线程上。spring-doc.cadn.net.cn

实体回调提供了与同步和响应式 API 的集成点,以确保在处理链中定义明确的检查点按顺序执行,并返回一个可能已被修改的实体或响应式包装类型。spring-doc.cadn.net.cn

实体回调通常按 API 类型进行区分。这种区分意味着同步 API 仅考虑同步实体回调,而响应式实现仅考虑响应式实体回调。spring-doc.cadn.net.cn

实体回调(Entity Callback)API 自 Spring Data Commons 2.2 起引入,是应用实体修改的推荐方式。 现有的特定于存储的 ApplicationEvents 仍会在调用已注册的 EntityCallback 实例之前发布。spring-doc.cadn.net.cn

实现实体回调

EntityCallback 通过其泛型类型参数直接与其领域类型相关联。 每个 Spring Data 模块通常都提供一组预定义的 EntityCallback 接口,用于覆盖实体的生命周期。spring-doc.cadn.net.cn

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() 的调用点推断得出。

实现符合您应用程序需求的接口,如下例所示:spring-doc.cadn.net.cn

示例 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,因此能够访问 ApplicationContextspring-doc.cadn.net.cn

以下示例说明了一组有效的实体回调注册:spring-doc.cadn.net.cn

示例 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 // ...
	}
}
1 BeforeSaveCallback@Order 注解接收其顺序。
2 BeforeSaveCallback 通过实现 Ordered 接口来接收其执行顺序。
3 使用 lambda 表达式实现的 BeforeSaveCallback。默认情况下无序,并在最后被调用。请注意,通过 lambda 表达式实现的回调不会暴露类型信息,因此使用不可赋值的实体调用这些回调会影响回调的吞吐量。请使用 classenum 来为回调 bean 启用类型过滤。
4 在单个实现类中组合多个实体回调接口。

特定存储的 EntityCallbacks

Spring Data for Apache Cassandra 使用 EntityCallback API 提供其审计支持,并响应以下回调。spring-doc.cadn.net.cn

表1. 支持的实体回调
回调 方法 描述 订单

ReactiveBeforeConvertCallback BeforeConvertCallbackspring-doc.cadn.net.cn

onBeforeConvert(T entity, CqlIdentifier tableName)spring-doc.cadn.net.cn

在领域对象被转换为Statement之前调用。 可以在Statement中更新领域对象以包含相应变更。spring-doc.cadn.net.cn

Ordered.LOWEST_PRECEDENCEspring-doc.cadn.net.cn

ReactiveAuditingEntityCallback AuditingEntityCallbackspring-doc.cadn.net.cn

onBeforeConvert(Object entity, CqlIdentifier tableName)spring-doc.cadn.net.cn

标记一个可审计实体为已创建已修改spring-doc.cadn.net.cn

100spring-doc.cadn.net.cn

ReactiveBeforeSaveCallback BeforeSaveCallbackspring-doc.cadn.net.cn

onBeforeSave(T entity, CqlIdentifier tableName, Statement statement)spring-doc.cadn.net.cn

在保存领域对象之前调用。
可以在之后修改目标对象Statement已创建。提供的语句包含所有映射的实体信息,但域对象的更改未包含在Statement.spring-doc.cadn.net.cn

Ordered.LOWEST_PRECEDENCEspring-doc.cadn.net.cn