AxonFramework,存儲(chǔ)庫

存儲(chǔ)庫是提供對(duì)聚合訪問的機(jī)制。存儲(chǔ)庫充當(dāng)了用于保存數(shù)據(jù)的實(shí)際存儲(chǔ)機(jī)制的網(wǎng)關(guān)。在CQRS中,存儲(chǔ)庫只需要能夠根據(jù)他們的惟一標(biāo)識(shí)符找到聚合。任何其他類型的查詢,應(yīng)該在查詢數(shù)據(jù)庫中執(zhí)行。

在Axon Framework中,所有存儲(chǔ)庫必須實(shí)現(xiàn)Repository接口。這個(gè)接口規(guī)定了三種方法:load(identifier, version), load(identifier)和newInstance(factoryMethod)。load方法允許你從存儲(chǔ)庫加載聚合。version可選參數(shù)是用來檢測(cè)并發(fā)修改(見Advanced conflict detection and resolution)。newInstance用于注冊(cè)新創(chuàng)建的聚合到存儲(chǔ)庫中。

基于你潛在的持久性存儲(chǔ)和審計(jì)需求,有一些基礎(chǔ)實(shí)現(xiàn)提供大了部分存儲(chǔ)庫所需的基本功能。Axon Framework對(duì)保存聚合當(dāng)前狀態(tài)的存儲(chǔ)庫(見Standard Repositories)和那些存儲(chǔ)聚合事件的存儲(chǔ)庫(見 Event Sourcing Repositories)進(jìn)行了區(qū)分。

注意,存儲(chǔ)庫接口沒有聲明delete(identifier)方法。刪除聚合是通過在一個(gè)聚合內(nèi)部調(diào)用AggregateLifecycle.markDeleted()方法完成的。刪除聚合是一個(gè)與其他遷移一樣的狀態(tài)遷移,唯一的區(qū)別是它在許多情況下是不可逆的。你應(yīng)該在聚合上創(chuàng)建自己的有意義的方法,來將聚合的狀態(tài)設(shè)置為“已刪除”。這也允許你注冊(cè)你想要發(fā)布的任何事件。

Standard repositories(標(biāo)準(zhǔn)存儲(chǔ)庫)

標(biāo)準(zhǔn)存儲(chǔ)庫存儲(chǔ)聚合的實(shí)際狀態(tài)。在每次修改后,新的狀態(tài)將覆蓋舊的。這使得命令組件也可以使用應(yīng)用程序的查詢組件使用的相同信息。標(biāo)準(zhǔn)存儲(chǔ)庫存儲(chǔ)聚合的實(shí)際狀態(tài)。這可能取決于你正在創(chuàng)建的應(yīng)用程序的類型,這是最簡(jiǎn)單的解決方案。如果是這樣的話,Axon提供了一些幫助你實(shí)現(xiàn)這樣一個(gè)存儲(chǔ)庫的構(gòu)件。

Axon為標(biāo)準(zhǔn)存儲(chǔ)庫提供了一個(gè)開箱即用的實(shí)現(xiàn):GenericJpaRepository。它認(rèn)為聚合是一個(gè)有效的JPA實(shí)體。它使用EntityManagerProvider配置,EntityManagerProvider提供EntityManager來管理實(shí)際的持久化,并且一個(gè)類指定聚合的實(shí)際類型存儲(chǔ)在存儲(chǔ)庫中。當(dāng)聚合調(diào)用靜態(tài)AggregateLifecycle.apply()方法時(shí),你也可以通過EventBus去發(fā)布事件。

你也可以輕松實(shí)現(xiàn)自己的存儲(chǔ)庫。在這種情況下,最好從抽象類LockingRepository擴(kuò)展。作為聚合的包裝器類型,建議使用AnnotatedAggregate。看GenericJpaRepository的源碼示例。

Event Sourcing repositories(事件溯源存儲(chǔ)庫)

聚合根能夠根據(jù)事件重建它們的狀態(tài),也可以配置為通過事件溯源存儲(chǔ)庫加載。這些存儲(chǔ)庫不存儲(chǔ)聚合本身,但存儲(chǔ)聚合生成的一系列事件?;谶@些事件,可以隨時(shí)恢復(fù)聚合的狀態(tài)。

在AxonFramework中,EventSourcingRepository實(shí)現(xiàn)提供了任何事件溯源存儲(chǔ)庫所需的基本功能。這依賴于EventStore(見Implementing your own Event Store),它抽象了實(shí)際的存儲(chǔ)機(jī)制。

根據(jù)情況,你可以提供一個(gè)聚合工廠。AggregateFactory指定了如何創(chuàng)建一個(gè)聚合實(shí)例。一旦創(chuàng)建了一個(gè)聚合,EventSourcingRepository可以使用從事件存儲(chǔ)中加載的事件來初始化。Axon Framework自帶了一些你可以使用的AggregateFactory實(shí)現(xiàn)。如果他們還不夠,可以很容易創(chuàng)建你自己的實(shí)現(xiàn)。

GenericAggregateFactory

GenericAggregateFactory是一種特別的AggregateFactory實(shí)現(xiàn),可用于任何類型的事件溯源聚合根。GenericAggregateFactory創(chuàng)建存儲(chǔ)庫管理的聚合類型的一個(gè)實(shí)例。聚合類必須是非抽象的,聲明一個(gè)默認(rèn)的不進(jìn)行初始化的無參構(gòu)造函數(shù)化。
GenericAggregateFactory適用于大多數(shù)場(chǎng)景,聚合不需要專門注入non-serializable資源。

SpringPrototypeAggregateFactory

根據(jù)你的架構(gòu)選擇,使用Spring將依賴項(xiàng)注入到聚合中可能是有用的。例如,你可以將查詢庫注入到你的聚合,以確保某些值的存在(或不存在)。

注入依賴項(xiàng)到你的聚合,在定義了SpringPrototypeAggregateFactory的Spring上下文中,你需要配置一個(gè)聚合根的屬性bean。不是使用構(gòu)造函數(shù)創(chuàng)建的常規(guī)的實(shí)例,而是使用Spring應(yīng)用程序上下文實(shí)例化你聚合。這也將在你的聚合中注入的任何依賴項(xiàng)。

實(shí)現(xiàn)自己的AggregateFactory

在某些情況下,GenericAggregateFactory不能提供你所需要的東西。例如,你可以有一個(gè)抽象的聚合類型與不同的場(chǎng)景的多個(gè)實(shí)現(xiàn)(例如,PublicUserAccount和BackOfficeAccount都擴(kuò)展一個(gè)帳戶)。而不是為每個(gè)聚合創(chuàng)建不同的存儲(chǔ)庫,你可以使用一個(gè)單獨(dú)的存儲(chǔ)庫,并配置一個(gè)AggregateFactory意識(shí)到不同的實(shí)現(xiàn)。

聚合工廠大部分的工作是創(chuàng)建未初始化的聚合實(shí)例。它必須使用一個(gè)給定的聚合標(biāo)識(shí)符和流中的第一個(gè)事件。通常,這個(gè)事件是一個(gè)創(chuàng)建事件,其中包含關(guān)于預(yù)期聚合類型的提示。你可以使用這些信息來選擇一個(gè)實(shí)現(xiàn)并調(diào)用其構(gòu)造函數(shù)。確保沒有事件被應(yīng)用于構(gòu)造函數(shù);聚合必須未初始化。

相對(duì)于簡(jiǎn)單的存儲(chǔ)庫直接加載聚合的實(shí)現(xiàn),基于事件初始化聚合可能是一項(xiàng)耗時(shí)的工作,。CachingEventSourcingRepository提供一個(gè)可以從中加載聚合的緩存

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容