實體回呼

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

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