Spring Data访问Elasticsearch----实体回调Entity Callbacks
Spring Data基础结构提供了钩子,用于在调用某些方法之前和之后修改实体。这些所谓的EntityCallback实例提供了一种方便的方式来检查并可能以回调风格修改实体。
EntityCallback看起来很像一个专门的ApplicationListener。一些Spring Data模块发布特定于存储的事件(如BeforeSaveEvent),允许修改给定的实体。在某些情况下,例如在处理不可变类型时,这些事件可能会造成麻烦。此外,事件发布依赖于ApplicationEventMulticaster。如果使用异步TaskExecutor进行配置,可能会导致不可预测的结果,因为事件处理可能会分叉到线程上。
实体回调为同步API和反应式(reactive)API提供了集成点,以保证在处理链中定义良好的检查点(checkpoints)按顺序执行,从而返回可能修改的实体或反应式包装器类型。
实体回调通常由API类型分隔。这种分离意味着同步API只考虑同步实体回调,而反应式实现只考虑反应式实体回调。
实体回调API是在Spring Data Commons 2.2中引入的。这是应用实体修改的推荐方式。在调用可能注册的EntityCallback实例之前,仍会发布现有的特定于存储的ApplicationEvents。
一、实现实体回调
EntityCallback通过其泛型类型参数与其域类型直接关联。每个Spring Data模块通常附带一组覆盖实体生命周期的预定义EntityCallback接口。
EntityCallback的剖析
java
@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. 许多存储特定的参数,如实体持久化到的集合。
反应式的EntityCallback剖析
java
@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. 在保存实体之前,在subscription上调用BeforeSaveCallback特定的方法。发出一个可能已修改的实例。
2. 就在持久化之前的实体。
3. 许多特定于存储的参数,如实体持久化到的集合。
可选的实体回调参数由实现的Spring Data模块定义,并从EntityCallback.callback()的调用位置推断。
实现适合您的应用程序需求的接口,如下面的示例所示:
示例BeforeSaveCallback
java
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. 如果同一域类型存在多个实体回调,则可能会对实体回调进行排序。排序遵循最低优先级。
二、注册实体回调
如果EntityCallback beans在ApplicationContext中注册,则由特定于存储的实现拾取。大多数template API已经实现ApplicationContextAware,因此可以访问ApplicationContext
以下示例解释了有效实体回调注册的集合:
EntityCallback Bean注册示例
java
@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表达式实现的回调不会公开类型信息,因此使用不可分配的实体调用这些信息会影响回调吞吐量。使用类或枚举为回调bean启用类型筛选。
4. 在一个实现类中组合多个实体回调接口。
三、存储特定的EntityCallbacks
Spring Data Elasticsearch在内部使用EntityCallback API来支持其auditing,并对以下回调做出反应:
表1:支持的实体回调
Callback | Method | Description | Order |
---|---|---|---|
Reactive/BeforeConvertCallback | onBeforeConvert(T entity, IndexCoordinates index) | 在域对象转换为org.springframework.data.elasticsearch.core.document.Document之前调用。可以返回实体或修改后的实体,然后将其转换。 | Ordered.LOWEST_PRECEDENCE |
Reactive/AfterLoadCallback | onAfterLoad(Document document, Class type, IndexCoordinates indexCoordinates) | 在从Elasticsearch得到的结果被读入org.springframework.data.elasticsearch.core.document.Document之后调用。 | Ordered.LOWEST_PRECEDENCE |
Reactive/AfterConvertCallback | onAfterConvert(T entity, Document document, IndexCoordinates indexCoordinates) | 在从Elasticsearch读取结果数据时,从"org.springframework.data.aelasticsearch.core.document.document"转换为域对象后调用。 | Ordered.LOWEST_PRECEDENCE |
Reactive/AuditingEntityCallback | onBeforeConvert(Object entity, IndexCoordinates index) | 标记创建或修改的可审核实体 | 100 |
Reactive/AfterSaveCallback | T onAfterSave(T entity, IndexCoordinates index) | 在保存域对象后调用。 | Ordered.LOWEST_PRECEDENCE |