Lifecycle Events

MongoDB 映射框架包含多个 org.springframework.context.ApplicationEvent 事件,您的应用程序可以通过在 ApplicationContext 中注册特殊 Bean 来响应这些事件。基于 Spring 的 ApplicationContext 事件基础设施的其他产品(例如 Spring Integration)可以轻松接收这些事件,因为它们是基于 Spring 的应用程序中的众所周知事件机制。 实体生命周期事件可能较为耗时,在加载大型结果集时,您可能会注意到性能曲线发生变化。您可以在 Template API 上禁用生命周期事件。 要在对象经过转换过程之前拦截它(它将域对象转换为 org.bson.Document),您可以注册覆盖 onBeforeConvert 方法的 AbstractMongoEventListener 的子类。当事件分发时,您的侦听器被调用并传递域对象,然后将其传给转换器。以下示例演示如何执行此操作:

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

要在对象进入数据库之前拦截它,您可以注册覆盖 onBeforeSave 方法的 org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener 的子类。当事件分发时,您的侦听器被调用并传递给域对象和已转换的 com.mongodb.Document。以下示例演示如何执行此操作:

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

在 Spring ApplicationContext 中声明这些 Bean 会让它们在事件被分派时被调用。 .Callbacks on AbstractMappingEventListener:

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

  • onBeforeSave:在 MongoTemplate insertinsertListsave 操作中调用,beforeDocument 插入或保存到数据库中。

  • onAfterSave:在 MongoTemplate insertinsertListsave 操作中调用,afterDocument 插入或保存到数据库中。

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

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

仅为根级别类型发出生命周期事件。如果未使用 @DBRef 注释文档根内的复杂类型(例如作为属性使用),则不会触发事件发布。

生命周期事件依赖 ApplicationEventMulticaster,在使用 SimpleApplicationEventMulticaster 的情况下,它可以通过 TaskExecutor 进行配置,因此无法保证事件的处理时间。

Entity Callbacks

Spring Data 基础设施提供了在调用某些方法之前和之后修改实体的挂钩方法。这些所谓的 EntityCallback 实例提供了一种便捷的方法在回调样式中检查和修改实体。一个 EntityCallback 非常类似于一个专门的 ApplicationListener。一些 Spring Data 模块发布特定于存储的事件(如 BeforeSaveEvent),允许修改给定的实体。在某些情况下,例如使用不可变类型时,这些事件可能会引起问题。此外,事件发布依赖于 ApplicationEventMulticaster。如果使用异步 TaskExecutor 来配置它,会导致不可预知的结果,因为事件处理可能会 fork 到一个线程中。 实体回调提供与同步和反应式 API 的集成点,以保证在处理链内的明确检查点中按顺序执行,返回一个可能修改后的实体或一个反应式包装器类型。 实体回调通常按 API 类型区分。这种划分表示,一个同步 API 仅考虑同步实体回调,而一个反应式实现仅考虑反应式实体回调。

实体回调 API 已在 Spring Data Commons 2.2 中引入。这是应用实体修改的推荐方式。现有的特定于存储的 ApplicationEvents 仍会在调用可能已注册的 EntityCallback 实例 之前 发布。

Implementing Entity Callbacks

EntityCallback 通过其泛型类型参数直接与它的领域类型相关联。每个 Spring Data 模块通常会提供一组预定义的 EntityCallback 接口,涵盖实体生命周期。

Anatomy of an 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)
}
1 BeforeSaveCallback 在实体保存之前需要调用的特定方法。返回一个可能修改的实例。
2 在持久化之前,该实体。
3 许多商店特定参数,例如_collection_ 实体被持久化到的参数。
Anatomy of a reactive EntityCallback
@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)
}
1 BeforeSaveCallback 在订阅中调用的特定方法,在实体保存之前。发送一个可能修改的实例。
2 在持久化之前,该实体。
3 许多商店特定参数,例如_collection_ 实体被持久化到的参数。

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

根据你的应用程序需要实现这个界面,如下面的示例中所示:

Example 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
	}
}
1 根据您的要求实现回调。
2 如果同一域类型的实体回调存在多个,请尽可能对实体回调进行排序。排序按照优先级最低的顺序进行。

Registering Entity Callbacks

如果它们在 ApplicationContext 中注册,商店特定实现将选取 EntityCallback bean。大多数模板 API 已实现 ApplicationContextAware,因此可以访问 ApplicationContext

以下示例说明了一系列有效的实体回调注册:

Example EntityCallback Bean registration
@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 // ...
	}
}
1 BeforeSaveCallback 从`@Order` 注释中收到其顺序。
2 BeforeSaveCallback 通过`Ordered` 接口实现接收其顺序。
3 BeforeSaveCallback 使用 lambda 表达式。默认情况下无序,最后调用。注意,由 lambda 表达式实现的回调不会公开类型信息,因此用不可分配实体调用这些回调会影响回调吞吐量。使用`class` 或`enum` 为回调 bean 启用类型筛选。
4 在单个实现类中组合多个实体回调接口。

Store specific EntityCallbacks

Spring Data MongoDB 对其审计支持使用 EntityCallback API,并对以下回调做出反应。

Table 1. Supported Entity Callbacks
Callback Method Description Order

ReactiveBeforeConvertCallback BeforeConvertCallback

onBeforeConvert(T entity, String collection)

在领域对象转换为 org.bson.Document 之前调用。

Ordered.LOWEST_PRECEDENCE

ReactiveAfterConvertCallback AfterConvertCallback

onAfterConvert(T entity, org.bson.Document target, String collection)

在加载完领域对象后调用。可以在从 org.bson.Document 中读取领域对象后对其进行修改。

Ordered.LOWEST_PRECEDENCE

ReactiveAuditingEntityCallback AuditingEntityCallback

onBeforeConvert(Object entity, String collection)

标记可审核的实体 createdmodified

100

ReactiveBeforeSaveCallback BeforeSaveCallback

onBeforeSave(T entity, org.bson.Document target, String collection)

在保存领域对象之前调用。可以修改要持久化的目标 Document(包含所有映射的实体信息)。

Ordered.LOWEST_PRECEDENCE

ReactiveAfterSaveCallback AfterSaveCallback

onAfterSave(T entity, org.bson.Document target, String collection)

在保存领域对象之前调用。可以在保存后修改要返回的领域对象 Document(包含所有映射的实体信息)。

Ordered.LOWEST_PRECEDENCE