生命周期事件
Spring Data JDBC 发布生命周期事件到 ApplicationListener
对象,通常是应用上下文中的 bean。事件是关于某个生命周期阶段的通知。与实体回调不同,事件是用于通知的。事务监听器将在事务完成时接收事件。事件和回调仅对聚合根触发。如果你想处理非根实体,你需要通过包含的聚合根的监听器来进行处理。
实体生命周期事件可能代价高昂,在加载大型结果集时,你可能会注意到性能特征的变化。你可以在 Template API 上禁用生命周期事件。
例如,以下监听器在聚合保存之前被调用:
@Bean
ApplicationListener<BeforeSaveEvent<Object>> loggingSaves() {
return event -> {
Object entity = event.getEntity();
LOG.info("{} is getting saved.", entity);
};
}
如果你想仅处理特定领域类型的事件,可以从 AbstractRelationalEventListener
派生你的监听器,并重写一个或多个 onXXX
方法,其中 XXX
代表事件类型。回调方法仅会在与领域类型及其子类型相关的事件时被调用,因此你不需要进一步进行类型转换。
class PersonLoadListener extends AbstractRelationalEventListener<Person> {
@Override
protected void onAfterLoad(AfterLoadEvent<Person> personLoad) {
LOG.info(personLoad.getEntity());
}
}
下表描述了可用的事件。有关流程步骤之间确切关系的更多详细信息,请参阅 可用回调的描述,其中回调与事件一一对应。
表 1. 可用事件
事件 | 发布时机 |
---|---|
BeforeDeleteEvent | 在一个聚合根被删除之前。 |
AfterDeleteEvent | 在一个聚合根被删除之后。 |
BeforeConvertEvent | 在一个聚合根被转换为执行 SQL 语句的计划之前,但在决定该聚合根是新的还是旧的之后,即决定是更新还是插入。 |
BeforeSaveEvent | 在一个聚合根被保存之前(即插入或更新,但在决定是插入还是更新之后)。 |
AfterSaveEvent | 在一个聚合根被保存之后(即插入或更新)。 |
AfterConvertEvent | 在一个聚合根从数据库 ResultSet 中创建并且所有属性都被设置之后。 |
注意
生命周期事件依赖于 ApplicationEventMulticaster
,在使用 SimpleApplicationEventMulticaster
时,可以配置一个 TaskExecutor
,因此无法保证事件何时被处理。
特定于存储的 EntityCallbacks
Spring Data JDBC 使用 EntityCallback API 来支持审计功能,并响应下表中列出的回调。
表 2. Spring Data JDBC 执行的不同流程的步骤和回调。
过程 | EntityCallback / 处理步骤 | 注释 |
---|---|---|
删除 | BeforeDeleteCallback | 在实际删除之前。 |
聚合根及其所有实体将从数据库中移除。 | ||
AfterDeleteCallback | 在聚合被删除之后。 | |
保存 | 根据聚合是否为新的来决定是执行插入还是更新操作。 | |
BeforeConvertCallback | 如果你想以编程方式设置 ID,这是正确的回调。在前一步骤中,新的聚合被检测为新的,并且在此步骤中生成的 ID 将在后续步骤中使用。 | |
将聚合转换为聚合更改,它是一系列要针对数据库执行的 SQL 语句。在此步骤中,决定是聚合提供 ID 还是 ID 仍然为空,并预期由数据库生成。 | ||
BeforeSaveCallback | 对聚合根的更改可能会被考虑,但是否将 ID 值发送到数据库的决定已经在前一步骤中做出。不要使用此回调来为新聚合创建 ID。请改用 BeforeConvertCallback 。 | |
上述确定的 SQL 语句将在数据库中执行。 | ||
AfterSaveCallback | 在聚合根被保存(即插入或更新)之后。 | |
加载 | 使用 1 个或多个 SQL 查询加载聚合。从结果集构建聚合。 | |
AfterConvertCallback |
我们鼓励使用回调而不是事件,因为回调支持使用不可变类,因此比事件更强大和灵活。