跳到主要内容

生命周期事件

DeepSeek V3 中英对照 Lifecycle Events

MongoDB 映射框架包含了多个 org.springframework.context.ApplicationEvent 事件,您的应用程序可以通过在 ApplicationContext 中注册特殊的 bean 来响应这些事件。由于这些事件基于 Spring 的 ApplicationContext 事件基础设施,因此其他产品(如 Spring Integration)可以轻松接收这些事件,因为它们是基于 Spring 的应用程序中众所周知的事件机制。

实体生命周期事件可能会带来较大的开销,在加载大规模结果集时,你可能会注意到性能特征的变化。你可以在 Template API 上禁用生命周期事件。

要在对象经过转换过程(将你的领域对象转换为 org.bson.Document)之前拦截它,你可以注册一个 AbstractMongoEventListener 的子类,并重写 onBeforeConvert 方法。当事件被触发时,你的监听器会被调用,并在对象进入转换器之前传递给它。以下示例展示了如何实现这一点:

public class BeforeConvertListener extends AbstractMongoEventListener<Person> {
@Override
public void onBeforeConvert(BeforeConvertEvent<Person> event) {
... does some auditing manipulation, set timestamps, whatever ...
}
}
java

要在对象进入数据库之前拦截它,你可以注册一个继承自 AbstractMongoEventListener 的子类,并重写 onBeforeSave 方法。当事件被触发时,你的监听器会被调用,并传入领域对象和转换后的 com.mongodb.Document。以下示例展示了如何实现这一点:

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

在您的 Spring ApplicationContext 中声明这些 bean 会导致每当事件被派发时它们被调用。

AbstractMappingEventListener 上的回调方法:

  • onBeforeConvert: 在 MongoTemplateinsertinsertListsave 操作中,对象通过 MongoConverter 转换为 Document 之前调用。

  • onBeforeSave: 在 MongoTemplateinsertinsertListsave 操作中,Document 插入或保存到数据库之前调用。

  • onAfterSave: 在 MongoTemplateinsertinsertListsave 操作中,Document 插入或保存到数据库之后调用。

  • onAfterLoad: 在 MongoTemplatefindfindAndRemovefindOnegetCollection 方法中,从数据库检索到 Document 之后调用。

  • onAfterConvert: 在 MongoTemplatefindfindAndRemovefindOnegetCollection 方法中,从数据库检索到 Document 并将其转换为 POJO 之后调用。

备注

生命周期事件仅针对根级别类型触发。在文档根中作为属性使用的复杂类型不会触发事件发布,除非它们是使用 @DBRef 注解的文档引用。

注意

生命周期事件依赖于 ApplicationEventMulticaster,在使用 SimpleApplicationEventMulticaster 的情况下,可以通过配置 TaskExecutor 来实现,因此无法保证事件何时被处理。

实体回调

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

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

Entity Callbacks 通常按照 API 类型进行区分。这种区分意味着同步 API 仅考虑同步的 Entity Callbacks,而响应式实现仅考虑响应式的 Entity Callbacks。

备注

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 是一个在实体保存之前调用的特定方法。返回一个可能被修改的实例。

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

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

@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() 的调用位置推断。

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

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 MongoDB 使用 EntityCallback API 来支持审计功能,并响应以下回调事件。

表 1. 支持的实体回调

回调方法描述顺序
ReactiveBeforeConvertCallback BeforeConvertCallbackonBeforeConvert(T entity, String collection)在领域对象转换为 org.bson.Document 之前调用。Ordered.LOWEST_PRECEDENCE
ReactiveAfterConvertCallback AfterConvertCallbackonAfterConvert(T entity, org.bson.Document target, String collection)在领域对象加载后调用。
可以在从 org.bson.Document 读取后修改领域对象。
Ordered.LOWEST_PRECEDENCE
ReactiveAuditingEntityCallback AuditingEntityCallbackonBeforeConvert(Object entity, String collection)标记一个可审计实体为 已创建已修改100
ReactiveBeforeSaveCallback BeforeSaveCallbackonBeforeSave(T entity, org.bson.Document target, String collection)在领域对象保存之前调用。
可以修改目标文档,该文档包含所有映射的实体信息,以便持久化。
Ordered.LOWEST_PRECEDENCE
ReactiveAfterSaveCallback AfterSaveCallbackonAfterSave(T entity, org.bson.Document target, String collection)在领域对象保存之前调用。
可以修改领域对象,该对象将在保存后返回,包含所有映射的实体信息。
Ordered.LOWEST_PRECEDENCE