跳到主要内容
版本:4.4.3

生命周期事件

ChatGPT-4o-mini 中英对照 Lifecycle Events

Cassandra 映射框架有几个内置的 org.springframework.context.ApplicationEvent 事件,您的应用程序可以通过在 ApplicationContext 中注册特殊的 bean 来响应这些事件。基于 Spring 的应用上下文事件基础设施使得其他产品,如 Spring Integration,可以轻松接收这些事件,因为它们是 Spring 基于应用程序的一个众所周知的事件机制。

为了在对象进入数据库之前拦截它,您可以注册一个 AbstractCassandraEventListener 的子类,并重写 onBeforeSave(…) 方法。当事件被分发时,您的监听器会被调用,并传递域对象(这是一个 Java 实体)。实体生命周期事件可能会很耗费资源,当加载大型结果集时,您可能会注意到性能特征的变化。您可以在 Template API 上禁用生命周期事件。以下示例使用 onBeforeSave 方法:

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

在您的 Spring ApplicationContext 中声明这些 beans 将导致它们在事件被派发时被调用。

AbstractCassandraEventListener 具有以下回调方法:

  • onBeforeSave: 在 CassandraTemplate.insert(…) 和 .update(…) 操作中调用,作用是在插入或更新数据库中的一行数据之前,但在创建 Statement 之后。

  • onAfterSave: 在 CassandraTemplate.insert(…) 和 .update(…) 操作中调用,作用是在插入或更新数据库中的一行数据之后。

  • onBeforeDelete: 在 CassandraTemplate.delete(…) 操作中调用,作用是在删除数据库中的一行数据之前。

  • onAfterDelete: 在 CassandraTemplate.delete(…) 操作中调用,作用是在删除数据库中的一行数据之后。

  • onAfterLoad: 在 CassandraTemplate.select(…)、.slice(…) 和 .stream(…) 方法中调用,作用是在从数据库中检索每一行数据之后。

  • onAfterConvert: 在 CassandraTemplate.select(…)、.slice(…) 和 .stream(…) 方法中调用,作用是在将从数据库中检索到的一行数据转换为 POJO 后。

备注

生命周期事件仅对根级类型触发。作为聚合根属性使用的复杂类型不受事件发布的影响。

实体回调​

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

实体回调提供了与同步和反应式 API 的集成点,以确保在处理链中的明确定义的检查点按顺序执行,返回可能已修改的实体或反应式包装类型。

实体回调通常按 API 类型进行区分。这种区分意味着同步 API 只考虑同步实体回调,而响应式实现只考虑响应式实体回调。

备注

实体回调 API 是在 Spring Data Commons 2.2 中引入的。这是应用实体修改的推荐方式。现有的存储特定 ApplicationEvents 仍然在调用潜在注册的 EntityCallback 实例 之前 发布。

实现实体回调​

EntityCallback 通过其泛型类型参数直接与其领域类型关联。每个 Spring Data 模块通常会提供一组预定义的 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
}
  • BeforeSaveCallback 是在实体保存之前调用的特定方法。返回一个可能被修改过的实例。

  • 实体在持久化之前的状态。

  • 一些特定于存储的参数,例如实体被持久化到的 集合。

@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
}
  • BeforeSaveCallback 特定方法在订阅时调用,在实体被保存之前。发出一个可能已修改的实例。

  • 实体在持久化之前的状态。

  • 一些存储特定的参数,比如实体被持久化到的 集合。

备注

可选的实体回调参数由实现的 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
}
}
  • 根据您的要求实现回调。

  • 如果同一领域类型存在多个回调,可能需要对实体回调进行排序。排序遵循最低优先级。

注册实体回调​

EntityCallback beans 会被特定存储实现类拾取,前提是它们在 ApplicationContext 中被注册。大多数模板 API 已经实现了 ApplicationContextAware,因此可以访问 ApplicationContext。

以下示例解释了有效实体回调注册的集合:

@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 // ...
}
}
  • BeforeSaveCallback 接收来自 @Order 注解的顺序。

  • BeforeSaveCallback 通过实现 Ordered 接口接收顺序。

  • BeforeSaveCallback 使用 lambda 表达式。默认无序并最后调用。请注意,lambda 表达式实现的回调不暴露类型信息,因此使用不可赋值的实体调用这些回调会影响回调吞吐量。请使用 class 或 enum 来启用回调 bean 的类型过滤。

  • 在单一实现类中结合多个实体回调接口。

存储特定的 EntityCallbacks​

Spring Data for Apache Cassandra 使用 EntityCallback API 来支持审计,并在以下回调中作出反应。

表格 1. 支持的实体回调

回调函数方法描述顺序
ReactiveBeforeConvertCallback BeforeConvertCallbackonBeforeConvert(T entity, CqlIdentifier tableName)在域对象转换为 Statement 之前调用。域对象可以被更新,以包括 Statement 中的变化。Ordered.LOWEST_PRECEDENCE
ReactiveAuditingEntityCallback AuditingEntityCallbackonBeforeConvert(Object entity, CqlIdentifier tableName)标记一个可审计的实体 已创建 或 已修改100
ReactiveBeforeSaveCallback BeforeSaveCallbackonBeforeSave(T entity, CqlIdentifier tableName, Statement statement)在域对象保存之前调用。
可以在创建 Statement 后修改目标对象。提供的 Statement 包含所有映射的实体信息,但域对象的更改不包含在 Statement 中。
Ordered.LOWEST_PRECEDENCE