實體回撥
Spring Data 基礎設施提供了在呼叫某些方法之前和之後修改實體的鉤子。這些所謂的 EntityCallback
例項提供了一種便捷的方式,可以以回撥的方式檢查並可能修改實體。
一個 EntityCallback
非常類似於一個特化的 ApplicationListener
。一些 Spring Data 模組釋出特定於儲存的事件(例如 BeforeSaveEvent
),允許修改給定實體。在某些情況下,例如處理不可變型別時,這些事件可能會引起問題。此外,事件釋出依賴於 ApplicationEventMulticaster
。如果將其配置為非同步 TaskExecutor
,由於事件處理可能會分派到其他執行緒,這可能導致不可預測的結果。
實體回撥提供了與同步和響應式 API 的整合點,以確保在處理鏈中明確定義的檢查點按順序執行,並返回一個可能已修改的實體或一個響應式包裝型別。
實體回撥通常按 API 型別劃分。這種劃分意味著同步 API 只考慮同步實體回撥,而響應式實現只考慮響應式實體回撥。
實體回撥 API 已在 Spring Data Commons 2.2 中引入。它是應用實體修改的推薦方式。現有的特定於儲存的 |
實現實體回撥
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 | 一些特定於儲存的引數,例如實體將被持久化到的 *集合*。 |
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 | 一些特定於儲存的引數,例如實體將被持久化到的 *集合*。 |
可選的實體回撥引數由實現 Spring Data 模組定義,並從 EntityCallback.callback() 的呼叫點推斷。 |
實現適合你應用需求的介面,如下面示例所示
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 | 如果同一領域型別存在多個實體回撥,可以潛在地對它們進行排序。排序遵循最低優先順序的原則。 |
註冊實體回撥
如果 EntityCallback
bean 在 ApplicationContext
中註冊,它們會被特定於儲存的實現獲取。大多數模板 API 都已經實現了 ApplicationContextAware
,因此可以訪問 ApplicationContext
。
以下示例解釋了一系列有效的實體回撥註冊方式
EntityCallback
Bean 註冊示例@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 | 使用 lambda 表示式的 BeforeSaveCallback 。預設無序且最後呼叫。請注意,由 lambda 表示式實現的回撥不暴露型別資訊,因此使用不可賦值的實體呼叫它們會影響回撥吞吐量。使用 class 或 enum 來啟用回撥 bean 的型別過濾。 |
4 | 在一個實現類中結合多個實體回撥介面。 |