實體回呼

Spring Data 基礎架構提供了鉤點,用於在調用特定方法之前和之後修改實體。這些所謂的 EntityCallback 實例提供了一種方便的方式,以回呼方式檢查並可能修改實體。
EntityCallback 看起來很像特製化的 ApplicationListener。某些 Spring Data 模組發布特定於儲存區的事件 (例如 BeforeSaveEvent),允許修改給定的實體。在某些情況下,例如使用不可變類型時,這些事件可能會造成麻煩。此外,事件發布依賴於 ApplicationEventMulticaster。如果使用非同步 TaskExecutor 配置它,可能會導致不可預測的結果,因為事件處理可能會分支到一個執行緒。

實體回呼提供了與同步和反應式 API 的整合點,以保證在處理鏈中明確定義的檢查點按順序執行,並返回可能修改的實體或反應式包裝器類型。

實體回呼通常按 API 類型分隔。這種分離意味著同步 API 僅考慮同步實體回呼,而反應式實作僅考慮反應式實體回呼。

實體回呼 API 已在 Spring Data Commons 2.2 中引入。這是應用實體修改的建議方式。現有的特定於儲存區的 ApplicationEvents 仍然在調用可能已註冊的 EntityCallback 實例之前發布。

實作實體回呼

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 BeforeSaveCallback 使用 lambda 表達式。預設為無序且最後調用。請注意,通過 lambda 表達式實作的回呼不公開類型資訊,因此使用不可指派的實體調用這些回呼會影響回呼吞吐量。使用 classenum 來為回呼 bean 啟用類型篩選。
4 在單個實作類中組合多個實體回呼介面。