Lifecycle Events
Cassandra 映射框架具有多个内置的 org.springframework.context.ApplicationEvent
事件,您的应用程序可以通过在 ApplicationContext
中注册特殊 bean 来对此作出响应。基于 Spring 的应用程序上下文事件基础设施可以使其他产品(如 Spring Integration)轻松接收这些事件,因为它们是基于 Spring 应用程序中众所周知的事件机制。
为了在对象进入数据库之前对其进行拦截,您可以注册 org.springframework.data.cassandra.core.mapping.event.AbstractCassandraEventListener
的一个子类,该类会覆盖 onBeforeSave(…)
方法。分发事件时,您的监听器会调用并传递该域对象(该对象是一个 Java 实体)。实体生命周期事件可能代价很高,在加载大结果集时,您可能会注意性能曲线发生变化。您可以关闭 Template API 上的实体生命周期事件。以下示例使用 onBeforeSave
方法:
/*
* Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.example.mapping;
import org.springframework.data.cassandra.core.mapping.event.AbstractCassandraEventListener;
import org.springframework.data.cassandra.core.mapping.event.BeforeSaveEvent;
// tag::class[]
class BeforeSaveListener extends AbstractCassandraEventListener<Person> {
@Override
public void onBeforeSave(BeforeSaveEvent<Person> event) {
// … change values, delete them, whatever …
}
}
// end::class[]
在 Spring ApplicationContext
中声明这些 bean 将导致在发出事件时调用它们。
AbstractCassandraEventListener
具有以下回调方法:
-
5.
onBeforeSave
:在插入或更新数据库中一行之前,在`CassandraTemplate.insert(…)和
.update(…)`操作中调用,但在创建`Statement`之后。 -
6.
onAfterSave
:在插入或更新数据库中一行之后,在`CassandraTemplate…insert(…)和
.update(…)`操作中调用。 -
7.
onBeforeDelete
:在从数据库删除行之前,在`CassandraTemplate.delete(…)`操作中调用。 -
8.
onAfterDelete
:在从数据库删除行之后,在`CassandraTemplate.delete(…)`操作中调用。 -
9.
onAfterLoad
:在从数据库检索到每一行后,在`CassandraTemplate.select(…)、
.slice(…)和
.stream(…)`方法中调用。 -
10.
onAfterConvert
:在将从数据库检索到的行转换为POJO之后,在`CassandraTemplate.select(…)、
.slice(…)和
.stream(…)`方法中调用。
仅为根级别类型发布生命周期事件。在聚合根中用作属性的复杂类型不受事件发布的影响。 |
Entity Callbacks
Spring Data 基础设施提供了在调用某些方法之前和之后修改实体的挂钩方法。这些所谓的 EntityCallback
实例提供了一种便捷的方法在回调样式中检查和修改实体。一个 EntityCallback
非常类似于一个专门的 ApplicationListener
。一些 Spring Data 模块发布特定于存储的事件(如 BeforeSaveEvent
),允许修改给定的实体。在某些情况下,例如使用不可变类型时,这些事件可能会引起问题。此外,事件发布依赖于 ApplicationEventMulticaster
。如果使用异步 TaskExecutor
来配置它,会导致不可预知的结果,因为事件处理可能会 fork 到一个线程中。
实体回调提供与同步和反应式 API 的集成点,以保证在处理链内的明确检查点中按顺序执行,返回一个可能修改后的实体或一个反应式包装器类型。
实体回调通常按 API 类型区分。这种划分表示,一个同步 API 仅考虑同步实体回调,而一个反应式实现仅考虑反应式实体回调。
实体回调 API 已在 Spring Data Commons 2.2 中引入。这是应用实体修改的推荐方式。现有的特定于存储的 |
Implementing Entity Callbacks
EntityCallback
通过其泛型类型参数直接与它的领域类型相关联。每个 Spring Data 模块通常会提供一组预定义的 EntityCallback
接口,涵盖实体生命周期。
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_ 实体被持久化到的参数。 |
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 模块定义,并从 |
根据你的应用程序需要实现这个界面,如下面的示例中所示:
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
以下示例说明了一系列有效的实体回调注册:
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 for Apache Cassandra 使用 EntityCallback
API 进行审计支持,并对以下回调做出反应。
Callback | Method | Description | Order |
---|---|---|---|
|
|
在将域对象转换为 |
|
|
|
标记可审核的实体 created 或 modified |
100 |
|
|
在保存域对象之前调用。可以在创建 |
|