跳到主要内容

生命周期事件

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 …
}
}
java

在您的 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
}
java
  • 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
}
java
  • 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
}
}
java
  • 根据您的要求实现回调。

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

注册实体回调

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

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

  • BeforeSaveCallback 使用 lambda 表达式。默认无序并最后调用。请注意,lambda 表达式实现的回调不暴露类型信息,因此使用不可赋值的实体调用这些回调会影响回调吞吐量。请使用 classenum 来启用回调 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