跳到主要内容

实体回调

Doubao 中英对照 Entity Callbacks

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

实体回调为同步 API 和响应式 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 的特定方法,在实体保存之前调用。返回一个可能被修改的实例。

  • 即将持久化之前的实体。

  • 若干特定存储的参数,例如实体要持久化到的 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("user".equals(collection)) {
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
  • 从 @Order 注解获取其顺序的 BeforeSaveCallback。

  • 通过 Ordered 接口实现获取其顺序的 BeforeSaveCallback。

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

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