生命周期事件
Spring Data JDBC 向 ApplicationListener 对象发布生命周期事件,这些对象通常是应用程序上下文中的 bean。事件是关于某个生命周期阶段的通知。与实体回调不同,事件用于通知。事务性监听器会在事务完成时收到事件。事件和回调仅对聚合根触发。如果您想处理非根实体,则需要通过监听其所从属的聚合根来完成。
实体生命周期事件可能开销较大,您在加载大型结果集时可能会注意到性能特征的变化。您可以在模板 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 | 在聚合根被保存之后(即插入或更新之后)。 | |
| 加载 | 使用一条或多条 SQL 查询加载聚合。从结果集构造聚合。 | |
| AfterConvertCallback |
我们鼓励使用回调而非事件,因为回调支持不可变类的使用,因此比事件更强大、更通用。
删除和保存相关的回调不会针对派生查询方法或注解查询被调用。一般而言,Spring Data JDBC 没有高效的方式来确定这些操作会影响哪些聚合,因此无法提供回调或事件。