在上一篇中,我們講述了CQRS和Event Sourcing的相關概念以及他們能解決什麼問題。儘管可以在不適用任何其他框架或庫的情況下實現CQRS/ES,但我們還是建議使用已有的一些工具。這些工具可以簡化開發過程,同時執行開發人員專注於業務邏輯的處理,避免重複的造輪子。在本節中,我們將選擇Axon框架來實現CQRS/ES。
什麼是Axon?
Axon是一個輕量級的Java開源框架,可以幫助構建你構建基於CQRS模式的可伸縮、可擴充套件和庫維護的Java應用程式。它還可以幫助你準備Event Sourcing所需要的環境。Axon提供了所有重要構建模組的實現,如聚合、儲存庫,命令和時間匯流排。Axon可以讓開發人員的工作更為輕鬆。
為何選擇Axon?
Axon讓我們避免了負載的配置和對資料流的操作,我們可以專注於應用程式業務規則的定製,而不是建立樣板程式碼。使用Axon可以獲得如下的一些優勢:
- 優化事件處理:我們應該注意到,事件的釋出具有先後順序。Axon框架保證了事件被執行的先後順序。
- 內建測試環境:Axon提供了一個測試工具集,允許在特定的時間上對系統進行測試,這使得單元測試更為容易。
- Spring Boot AutoConfiguration:在Spring Boot應用程式中配置Axon是一件非常簡單的事情。只需要提供必要的依賴項,Axon將會自動配置一些基本元件。
- 支援註解:Axon提供了註解支援,這使得我們的程式碼更清晰可讀,我們可以使用這些註解輕鬆構建聚合和事件處理程式,而無需關心Axon特定的處理邏輯
Spring Boot應用程式中快速配置Axon
在預設情況下,Axon以經提供了對Spring Boot的整合支援。我們只需要通過一些簡單的配置步驟就可以將Axon與Spring Boot整合在一起。
步驟1
第一步是使用合適的專案構建工具在專案中配置Axon依賴項。以下是使用Gradle來配置Axon的方法:
dependencies{
compile("org.axonframework:axon-spring-boot-starter:3.2")
compile("org.axonframework:axon-mongo:3.2")
testCompile("org.axonframework:axon-test:32.")
}
複製程式碼
第一個依賴項為我們提供了與Spring Boot整合的最基本的Axon所有必要元件,如命令中線,事件匯流排和聚合。第二個依賴項是為我們的聚合或事件配置庫提供所需的基本環境。最後一個依賴項用於構建先關的測試環境。
步驟2
根據需要配置Axon所需要的一些Spring Bean。比如EventHandlerConfiguration(負責控制事件處理程式行為的元件),如果其中有一個事件執行失敗,則終止處理後續的所有事件。當然這是非必須的,但是還是值得在應用程式中進行此配置,以防止系統中資料的不一致。配置程式碼如下:
@Configuration
public class AxonConfig {
private final EventHandlingConfiguration eventHandlingConfiguration;
@Autowired
public AxonConfig(EventHandlingConfiguration eventHandlingConfiguration) {
this.eventHandlingConfiguration = eventHandlingConfiguration;
}
@PostConstruct
public void registerErrorHandling() {
eventHandlingConfiguration.configureListenerInvocationErrorHandler(configuration -> (exception, event, listener) -> {
String msg = String.format(
"[EventHandling] Event handler failed when processing event with id %s. Aborting all further event handlers.",
event.getIdentifier());
log.error(msg, exception);
throw exception;
});
}}
複製程式碼
這裡的主要思想是建立一個額外的配置檔案(使用**@Configuration註釋的類)。該類的建構函式注入由Spring自身所管理的EventHandlingConfiguration依賴項。由於繫結依賴,我們可以在此物件上呼叫configureListenerInvocationErrorHandler()**並通過記錄異常將異常傳播到上層去處理錯誤。
步驟3
我們使用MongoDB來儲存Event Store中所發生的所有事件。要實現此功能,可以通過如下的方法來實現:
@Bean
public EventStorageEngine eventStore(MongoTemplate mongoTemplate) {
return new MongoEventStorageEngine(
new JacksonSerializer(), null, mongoTemplate, new DocumentPerEventStorageStrategy());
}
複製程式碼
這樣,在事件匯流排上釋出的所有事件都將自動儲存到MongoDB資料庫中。通過這種簡單的配置,我們就可以在應用程式中使用MongoDB的資料來源。
在Axon配置方面就是這樣的簡單。當然,我們還有其他很多的配置方式。但我們可以通過上述簡單的配置,就可以使用Axon的功能了。
使用Axon實現CQRS
根據上圖,建立命令,將命令傳遞給命令匯流排然後建立事件並將事件放在事件匯流排上還不是CQRS。我們必須記住改變寫入儲存庫的狀態並從讀取資料庫中讀取當前狀態,這才是CQRS模式的關鍵點。
配置此流程也並不複雜。在將命令傳遞給命令閘道器時,Spring將名利型別作為引數以搜尋帶有**@CommandHandler** 註釋的方法。
@Value
class SubmitApplicationCommand {
private String appId;
private String category;
}
@AllArgsConstructor
public class ApplicationService {
private final CommandGateway commandGateway;
public CompletableFuture<Void> createForm(String appId) {
return CompletableFuture.supplyAsync(() -> new SubmitExpertsFormCommand(appId, "Android"))
.thenCompose(commandGateway::send);
}
}
複製程式碼
除其他事項外,命令處理程式負責將建立的事件傳送到事件匯流排。它將事件物件放置到AggregateLifecycle靜態匯入的apply()方法中。然後排程該事件以查詢預期的處理程式,並且由於我們配置了事件儲存庫,所有事件都自動儲存在資料庫中。
@Value
class ApplicationSubmittedEvent {
private String appId;
private String category;
}
@Aggregate
@NoArgsConstructor
public class ApplicationAggregate {
@AggregateIdentifier
private String id;
@CommandHandler
public ApplicationAggregate(SubmitApplicationCommand command) {
//some validation
this.id = command.getAppId;
apply(new ApplicationSubmittedEvent(command.getAppId(), command.getCategory()));
}
}
複製程式碼
要更改寫庫的狀態,我們需要提供一個使用**@EventHandler**註釋的方法。該應用程式可以包含多個事件處理程式。他們每個人都應該執行一個特定的任務,如傳送電子郵件,記錄或儲存在資料庫中。
@RequiredArgsConstructor
@Order(1)
public class ProjectingEventHandler {
private final IApplicationSubmittedProjection projection;
@EventHandler
public CompletableFuture<Void> onApplicationSubmitted(ExpertsFormSubmittedEvent event) {
return projection.submitApplication(event.getApplicationId(), event.getCategory());
}
複製程式碼
如果我們想確定所有事件處理程式的處理順序,我們可以用**@Order**註釋一個類並設定一個序列號。**submitApplication()**方法負責進行所有必要的更改並將新的資料儲存到寫庫中。
這些都是使我們的應用程式採用CQRS模式原則的關鍵點。當然,這些原則只能應用於我們應用程式的某些部分,具體取決於業務需求。Event Sourcing不適合我們正在構建的每個應用程式或模組。在實現此模式時也要謹慎,因為更復雜的應用程式可能難以維護。
總結
使用Axon框架,CQRS和Event Sourcing的實現變得簡單化。有關高階配置的更多詳細資訊,請訪問Axon的網站docs.axonframework.org/。
原文作者:ŁukaszKucik
原文地址:www.nexocode.com/blog/posts/…
譯 者:譚朝紅