跳到主要内容

实体回调

DeepSeek V3 中英对照 Entity Callbacks

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

实体回调(Entity callbacks)提供了与同步和响应式 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
}
java
  • 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
}
java
  • BeforeSaveCallback 是在实体保存之前,在订阅上调用的特定方法。它发出一个可能被修改的实例。

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

  • 一些存储特定的参数,例如实体持久化到的 collection

备注

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

根据您的应用程序需求实现接口,如下例所示:

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 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 // ...
}
}
java
  • BeforeSaveCallback 通过 @Order 注解接收其顺序。

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

  • BeforeSaveCallback 使用 lambda 表达式。默认情况下无序并在最后调用。请注意,由 lambda 表达式实现的回调不会暴露类型信息,因此在调用这些回调时使用不可分配的实体会影响回调的吞吐量。使用 classenum 来启用回调 bean 的类型过滤。

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

特定于存储的 EntityCallbacks

Spring Data Elasticsearch 在内部使用 EntityCallback API 来支持审计功能,并对以下回调作出反应:

表 1. 支持的实体回调

回调方法描述顺序
Reactive/BeforeConvertCallbackonBeforeConvert(T entity, IndexCoordinates index)在领域对象转换为 org.springframework.data.elasticsearch.core.document.Document 之前调用。可以返回 entity 或一个修改后的实体,然后将其转换为文档。Ordered.LOWEST_PRECEDENCE
Reactive/AfterLoadCallbackonAfterLoad(Document document, Class<T> type, IndexCoordinates indexCoordinates)在从 Elasticsearch 读取结果并转换为 org.springframework.data.elasticsearch.core.document.Document 后调用。Ordered.LOWEST_PRECEDENCE
Reactive/AfterConvertCallbackonAfterConvert(T entity, Document document, IndexCoordinates indexCoordinates)在从 Elasticsearch 读取结果数据并将 org.springframework.data.elasticsearch.core.document.Document 转换为领域对象后调用。Ordered.LOWEST_PRECEDENCE
Reactive/AuditingEntityCallbackonBeforeConvert(Object entity, IndexCoordinates index)标记一个可审计实体的 创建修改100
Reactive/AfterSaveCallbackT onAfterSave(T entity, IndexCoordinates index)在领域对象保存后调用。Ordered.LOWEST_PRECEDENCE