Axon Framework命令模型

在一個基於CQRS的應用程序中,領域模型(由Eric Evans和Martin Fowler定義)可以是一個非常強大的機制,來駕馭在驗證和執行狀態的變化時所涉及的複雜性,雖然典型的領域模型提供了大量的構件,但當在CQRS中應用命令處理時有一個構件起着主導性的作用:聚合。

應用程序中的一個狀態的改變,始於一個命令。命令不但是表達意圖(描述你想要做什麼)的組合,而且是基於這一意圖採取行動所需的信息。命令模型用於處理傳入的命令,以驗證並定義它的結果。在這個模型中,一個命令處理器負責處理某種類型的命令,並根據它包含的信息採取行動。

聚合
聚合是一個總是保持一致性狀態的實體或一組實體。聚合根是聚合樹頂部負責維護這個一致性狀態的對象。這使得聚合主要構件在任何基於CQRS應用中實現命令模型。

注意
“聚合”指的是埃文斯在領域驅動設計中所定義的聚合:
”作爲數據變更的一個單元來處理的一組相關聯的對象。在外部只能引用聚合的聚合根對象。在聚合邊界內使用一組一致性規則。”

例如,“聯繫人”聚合可以包含兩個實體:聯繫人和地址。若要保持整個聚合處於一致性狀態,向聯繫人添加地址時應通過聯繫人實體完成。在這種情況下,聯繫人實體是約定的聚合根。

在Axon中,聚合由聚合標識符標識。這可能是任何對象,但也有一些標識符良好實現的指導原則。
標識符必須:

  • 實現equals和hashCode來保證與其他實例進行相等比較,
  • 實現一個提供一致結果的toString()方法(相等的標識符,toString()方法的結果也應該相等),
  • 並且最好是可序列化的。

當聚合使用不兼容標識符時,測試固件(見測試)將驗證這些條件並使測試失敗。 字符串類型的標識符,UUID和數值類型都適用。 不要使用原始類型作爲標識符,因爲它們不允許進行延遲初始化。在某些情況下,Axon可能會錯誤地假設原始類型的默認值是標識符的值。

注意
一個經過深思熟慮的好實踐是使用隨機生成的標識符,而不是使用序列。使用序列會大大降低應用程序的可伸縮性,因爲機器需要保持彼此最後一次使用的最新的序列號。UUID衝突的機率非常地小(假如你生成8.2乘以10的11次方個UUID,衝突的機率也只有10的負15次方)。

此外,聚合應小心地使用函數式標識符。因爲它們有變化的傾向,使得它很難適應相應的應用程序。

聚合的實現
聚合總是通過一個稱爲聚合根的實體訪問。通常,這個實體的名稱和聚合完全一樣。例如,Order聚合可能由Order實體引用幾個Orderline實體組合而成。Order 和Orderline一起形成聚合。

一個聚合是一個合乎規範的對象,其中包含狀態和和改變這個狀態的方法。雖然根據CQRS原則並不完全正確,也可能通過訪問器方法暴露出聚合的狀態。

聚合根必須聲明一個包含聚合標識符的字段。這個標識符字段必須最遲在第一個事件發佈時初始化。這個標識符字段必須由@AggregateIdentifier來註解。如果你在聚合上使用JPA註解,Axon也可以使用由JPA提供的@Id註解。

聚合可以使用AggregateLifecycle.apply()方法來註冊發佈的事件。與EventBus不同,這些信息需要被包裝在一個EventMessage中,apply()允許你直接傳遞負載對象。

@Entity // Mark this aggregate as a JPA Entity
public class MyAggregate {
@Id // When annotating with JPA @Id, the @AggregateIdentifier annotation is not ne
cessary
private String id;
// fields containing state...
@CommandHandler
public MyAggregate(CreateMyAggregateCommand command) {
// ... update state
apply(new MyAggregateCreatedEvent(...));
}
// constructor needed by JPA
protected MyAggregate() {
}
}

通過定義一個帶@EventHandler註解的方法,聚合內的實體能監聽聚合發佈的事件。當一個EventMessage發佈時這些方法將被調用(在任何外部處理器被髮布之前)。

發佈了40 篇原創文章 · 獲贊 2 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章