在上一篇中,咱们讲述了CQRS和Event Sourcing的相关概念以及他们能解决什么问题。尽管能够在不适用任何其余框架或库的状况下实现CQRS/ES,但咱们仍是建议使用已有的一些工具。这些工具能够简化开发过程,同时运行开发人员专一于业务逻辑的处理,避免重复的造轮子。在本节中,咱们将选择Axon框架来实现CQRS/ES。html
Axon是一个轻量级的Java开源框架,能够帮助构建你构建基于CQRS模式的可伸缩、可扩展和库维护的Java应用程序。它还能够帮助你准备Event Sourcing所须要的环境。Axon提供了全部重要构建模块的实现,如聚合、存储库,命令和时间总线。Axon可让开发人员的工做更为轻松。java
Axon让咱们避免了负载的配置和对数据流的操做,咱们能够专一于应用程序业务规则的定制,而不是建立样板代码。使用Axon能够得到以下的一些优点:spring
在默认状况下,Axon以经提供了对Spring Boot的集成支持。咱们只须要经过一些简单的配置步骤就能够将Axon与Spring Boot整合在一块儿。数据库
第一步是使用合适的项目构建工具在项目中配置Axon依赖项。如下是使用Gradle来配置Axon的方法:markdown
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全部必要组件,如命令中线,事件总线和聚合。第二个依赖项是为咱们的聚合或事件配置库提供所需的基本环境。最后一个依赖项用于构建先关的测试环境。app
根据须要配置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()**并经过记录异常将异常传播到上层去处理错误。函数
咱们使用MongoDB来存储Event Store中所发生的全部事件。要实现此功能,能够经过以下的方法来实现:spring-boot
@Bean public EventStorageEngine eventStore(MongoTemplate mongoTemplate) { return new MongoEventStorageEngine( new JacksonSerializer(), null, mongoTemplate, new DocumentPerEventStorageStrategy()); } 复制代码
这样,在事件总线上发布的全部事件都将自动保存到MongoDB数据库中。经过这种简单的配置,咱们就能够在应用程序中使用MongoDB的数据源。工具
在Axon配置方面就是这样的简单。固然,咱们还有其余不少的配置方式。但咱们能够经过上述简单的配置,就可使用Axon的功能了。
根据上图,建立命令,将命令传递给命令总线而后建立事件并将事件放在事件总线上还不是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/…
译 者:谭朝红