實體回呼

Spring Data 基礎架構提供了 Hook,用於在調用特定方法之前和之後修改實體。這些所謂的 EntityCallback 實例提供了一種方便的方式,以回呼風格檢查並可能修改實體。
EntityCallback 看起來很像一個專門的 ApplicationListener。某些 Spring Data 模組發佈商店特定的事件(例如 BeforeSaveEvent),允許修改給定的實體。在某些情況下,例如使用不可變類型時,這些事件可能會導致問題。此外,事件發佈依賴於 ApplicationEventMulticaster。如果使用異步 TaskExecutor 配置它,則可能會導致不可預測的結果,因為事件處理可能會 Fork 到一個 Thread。

實體回呼提供與同步和反應式 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 在單個實作類別中組合多個實體回呼介面。