跳到主要内容
版本:5.1.1

生命周期事件

Doubao 中英对照 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 中声明这些 bean,即可在事件派发时调用它们。

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,事件处理可能被分派到某个 Thread 上执行,从而导致不可预测的结果。

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

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

备注

Entity Callback 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 的专用方法,在实体保存前调用。返回一个可能被修改的实例。

  • 即将持久化的实体。

  • 若干特定存储的参数,例如实体要持久化到的 collection。

@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 的专用方法,在订阅时、实体保存前调用。发射一个可能被修改的实例。

  • 即将持久化的实体。

  • 若干特定存储的参数,例如实体要持久化到的 collection。

备注

可选的实体回调参数由实现它的 Spring Data 模块定义,并从 EntityCallback.callback() 的调用点推断得出。

请根据您的应用需要实现合适的接口,如下例所示:

class DefaultingEntityCallback implements BeforeSaveCallback<Person>, Ordered {      2

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

if("user".equals(collection)) {
return …;
}

return …;
}

@Override
public int getOrder() {
return 100; 2
}
}
  • 按您的需求实现的回调。

  • 如果同一领域类型存在多个实体回调,可以对其排序。排序遵循最低优先级原则。

注册实体回调​

如果 EntityCallback bean 注册在 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 // ...
}
}
  • 通过 @Order 注解指定顺序的 BeforeSaveCallback。

  • 通过实现 Ordered 接口指定顺序的 BeforeSaveCallback。

  • 使用 lambda 表达式的 BeforeSaveCallback。默认无序,最后调用。请注意,由 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 中。
Ordered.LOWEST_PRECEDENCE