Lifecycle Events
Cassandra 映射框架具有多个内置的 org.springframework.context.ApplicationEvent
事件,您的应用程序可以通过在 ApplicationContext
中注册特殊 bean 来对此作出响应。基于 Spring 的应用程序上下文事件基础设施可以使其他产品(如 Spring Integration)轻松接收这些事件,因为它们是基于 Spring 应用程序中众所周知的事件机制。
The Cassandra mapping framework has several built-in org.springframework.context.ApplicationEvent
events that your application can respond to by registering special beans in the ApplicationContext
.
Being based on Spring’s application context event infrastructure lets other products, such as Spring Integration, easily receive these events as they are a well known eventing mechanism in Spring-based applications.
为了在对象进入数据库之前对其进行拦截,您可以注册 org.springframework.data.cassandra.core.mapping.event.AbstractCassandraEventListener
的一个子类,该类会覆盖 onBeforeSave(…)
方法。分发事件时,您的监听器会调用并传递该域对象(该对象是一个 Java 实体)。实体生命周期事件可能代价很高,在加载大结果集时,您可能会注意性能曲线发生变化。您可以关闭 Template API 上的实体生命周期事件。以下示例使用 onBeforeSave
方法:
To intercept an object before it goes into the database, you can register a subclass of org.springframework.data.cassandra.core.mapping.event.AbstractCassandraEventListener
that overrides the onBeforeSave(…)
method.
When the event is dispatched, your listener is called and passed the domain object (which is a Java entity).
Entity lifecycle events can be costly and you may notice a change in the performance profile when loading large result sets.
You can disable lifecycle events on the Template API.
The following example uses the onBeforeSave
method:
/*
* 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 将导致在发出事件时调用它们。
Declaring these beans in your Spring ApplicationContext
will cause them to be invoked whenever the event is dispatched.
AbstractCassandraEventListener
具有以下回调方法:
The AbstractCassandraEventListener
has the following callback methods:
-
onBeforeSave
: Called inCassandraTemplate.insert(…)
and.update(…)
operations before inserting or updating a row in the database but after creating theStatement
. -
onAfterSave
: Called inCassandraTemplate…insert(…)
and.update(…)
operations after inserting or updating a row in the database. -
onBeforeDelete
: Called inCassandraTemplate.delete(…)
operations before deleting row from the database. -
onAfterDelete
: Called inCassandraTemplate.delete(…)
operations after deleting row from the database. -
onAfterLoad
: Called in theCassandraTemplate.select(…)
,.slice(…)
, and.stream(…)
methods after each row is retrieved from the database. -
onAfterConvert
: Called in theCassandraTemplate.select(…)
,.slice(…)
, and.stream(…)
methods after converting a row retrieved from the database to a POJO.
仅为根级别类型发布生命周期事件。在聚合根中用作属性的复杂类型不受事件发布的影响。 |
Lifecycle events are emitted only for root-level types. Complex types used as properties within an aggregate root are not subject to event publication. |
Entity Callbacks
Spring Data 基础设施提供了在调用某些方法之前和之后修改实体的挂钩方法。这些所谓的 EntityCallback
实例提供了一种便捷的方法在回调样式中检查和修改实体。一个 EntityCallback
非常类似于一个专门的 ApplicationListener
。一些 Spring Data 模块发布特定于存储的事件(如 BeforeSaveEvent
),允许修改给定的实体。在某些情况下,例如使用不可变类型时,这些事件可能会引起问题。此外,事件发布依赖于 ApplicationEventMulticaster
。如果使用异步 TaskExecutor
来配置它,会导致不可预知的结果,因为事件处理可能会 fork 到一个线程中。
The Spring Data infrastructure provides hooks for modifying an entity before and after certain methods are invoked.
Those so called EntityCallback
instances provide a convenient way to check and potentially modify an entity in a callback fashioned style.
An EntityCallback
looks pretty much like a specialized ApplicationListener
.
Some Spring Data modules publish store specific events (such as BeforeSaveEvent
) that allow modifying the given entity. In some cases, such as when working with immutable types, these events can cause trouble.
Also, event publishing relies on ApplicationEventMulticaster
. If configuring that with an asynchronous TaskExecutor
it can lead to unpredictable outcomes, as event processing can be forked onto a Thread.
实体回调提供与同步和反应式 API 的集成点,以保证在处理链内的明确检查点中按顺序执行,返回一个可能修改后的实体或一个反应式包装器类型。
Entity callbacks provide integration points with both synchronous and reactive APIs to guarantee in-order execution at well-defined checkpoints within the processing chain, returning a potentially modified entity or an reactive wrapper type.
实体回调通常按 API 类型区分。这种划分表示,一个同步 API 仅考虑同步实体回调,而一个反应式实现仅考虑反应式实体回调。
Entity callbacks are typically separated by API type. This separation means that a synchronous API considers only synchronous entity callbacks and a reactive implementation considers only reactive entity callbacks.
实体回调 API 已在 Spring Data Commons 2.2 中引入。这是应用实体修改的推荐方式。现有的特定于存储的 The Entity Callback API has been introduced with Spring Data Commons 2.2. It is the recommended way of applying entity modifications.
Existing store specific |
Implementing Entity Callbacks
EntityCallback
通过其泛型类型参数直接与它的领域类型相关联。每个 Spring Data 模块通常会提供一组预定义的 EntityCallback
接口,涵盖实体生命周期。
An EntityCallback
is directly associated with its domain type through its generic type argument.
Each Spring Data module typically ships with a set of predefined EntityCallback
interfaces covering the entity lifecycle.
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 specific method to be called before an entity is saved. Returns a potentially modifed instance. |
2 | The entity right before persisting. |
3 | A number of store specific arguments like the collection the entity is persisted to. |
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 specific method to be called on subscription, before an entity is saved. Emits a potentially modifed instance. |
2 | The entity right before persisting. |
3 | A number of store specific arguments like the collection the entity is persisted to. |
可选项实体回调参数由实现的 Spring Data 模块定义,并从 |
Optional entity callback parameters are defined by the implementing Spring Data module and inferred from call site of |
根据你的应用程序需要实现这个界面,如下面的示例中所示:
Implement the interface suiting your application needs like shown in the example below:
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 | Callback implementation according to your requirements. |
2 | Potentially order the entity callback if multiple ones for the same domain type exist. Ordering follows lowest precedence. |
Registering Entity Callbacks
如果它们在 ApplicationContext
中注册,商店特定实现将选取 EntityCallback
bean。大多数模板 API 已实现 ApplicationContextAware
,因此可以访问 ApplicationContext
EntityCallback
beans are picked up by the store specific implementations in case they are registered in the ApplicationContext
.
Most template APIs already implement ApplicationContextAware
and therefore have access to the ApplicationContext
以下示例说明了一系列有效的实体回调注册:
The following example explains a collection of valid entity callback registrations:
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 receiving its order from the @Order annotation. |
2 | BeforeSaveCallback receiving its order via the Ordered interface implementation. |
3 | BeforeSaveCallback using a lambda expression. Unordered by default and invoked last. Note that callbacks implemented by a lambda expression do not expose typing information hence invoking these with a non-assignable entity affects the callback throughput. Use a class or enum to enable type filtering for the callback bean. |
4 | Combine multiple entity callback interfaces in a single implementation class. |
Store-specific EntityCallbacks
Spring Data for Apache Cassandra 使用 EntityCallback
API 进行审计支持,并对以下回调做出反应。
Spring Data for Apache Cassandra uses the EntityCallback
API for its auditing support and reacts on the following callbacks.
Callback | Method | Description | Order |
---|---|---|---|
|
|
Invoked before a domain object is converted to |
|
|
|
Marks an auditable entity created or modified |
100 |
|
|
Invoked before a domain object is saved.
Can modify the target object after the |
|