在新建项目中考虑 Axon

Considering Axon in greenfield project

几个月后我将开始一个新建项目。
该项目将包含大量业务逻辑,分布在多个 subdomains 中。是的,我们将使用 Domain Driven Design 的原则。 技术将包括 Spring, Spring Boot & Hibernate 个堆栈。

我正在寻找一些 Java 库来涵盖基础设施,例如:

我遇到了 Axon Framework。早有耳闻,具体不了解。所以我阅读了一些博文、一些文档并在 Youtube 上观看了一些广播。

看起来很有前途,我正在考虑使用它,因为我不想在基础设施方面一遍又一遍地重新发明。
所以我正在找人回答和澄清我的问题:

命令处理

Axon 使用 CommandHandlersvoid 方法。是否可以使它们 return 成为一个值(例如生成的业务 ID)或对象以用于通知业务操作?
这个方法会I/O阻塞对我来说不是问题。


本地与远程域事件发布

我想明确区分 localremote 域事件。 Local domain 事件应该只对本地子域可见和使用。是否可以配置事件消费同步 and/or 异步? 我的本地域事件可以是 'fat'。他们被允许携带更多数据,因为它不会跨越域边界。

Remote domain events 将是 'thin',因此只有远程域所需的最少数据。这种类型的操作事件需要始终处理异步。

是否可以将本地(胖)域事件转换为域边缘的远程(瘦)域事件? 'edge',我指的是基础设施方面。 这样,域模型不需要知道本地和远程域事件之间的区别。


CQRS同步

我的申请将包含 1 个(也许 2 个)core domainsseveral subdomains。一些域包含很多业务逻辑,需要 CQRS.
其他域名会更加 'crudy' 风格。 是否可以同步执行 CQRS
我想在添加异步处理等技术复杂性之前以这种方式开始。 Axon 这可能吗?
这也意味着域事件将存储在事件存储中而不使用 event sourcing.

可以在没有事件源的情况下使用 Axon 的 event store 吗? 投影的东西也一样,我只想投影域事件来构建我的读取模型。


模块化单体

我们将使用 modular monolith
这些天所有 microservices 东西都不是很时髦。虽然,我确信拥有一个整体,其中每个域都是完全分离的(应用程序代码和数据库架构),其中操作将以最终一致性的方式处理,并且域事件包含必要的数据。 稍后,如果有必要,迁移到 microservices architecture.

会更容易 Axon 是适合模块化整体架构的框架吗?有什么需要注意的吗?


完全分离的领域模型(持久性不可知)

域模型将与数据模型完全分离。 我们需要有一个存储库来读取数据模型(使用Hibernate)并在需要加载时使用data mapper创建聚合。
还需要另一种方式,需要将聚合转换并保存到数据模型中(使用数据映射器)。
此外,聚合的域事件需要存储到事件存储中并发布到本地或远程事件处理程序。

这会产生一些后果:

Axon 可以采用这种方法吗?我只看到使用直接 JPA(域模型 1 对 1 映射到实体)或事件源的示例。
这种方法对我们来说确实是一个大问题,一个分离的领域模型比直接映射到数据实体提供了更多的可能性。

下面是我想要实现的示例:

在某些域模型包中聚合(没有 JPA):

public class ScoringResultAggregate {
  // members, constructor, operation omitted for brevity
}

一些基础设施包中的 Hibernate 实体:

@Entity
@Table(name ="SOME_TABLE_NAME)
public class ScoringResultEntity {
  // member and getters & setters; no domain logic
}

属于域模型的存储库接口:

public interface ScoringResultRepository {
  void save(ScoringResultAggregate scoringResultAggregate);

  ScoringResultAggregate findByApplicationNumber(ApplicationNumber applicationNumber);
}

实现存储库接口的适配器;负责映射聚合 from/to 数据 (JPA) 模型:

class ScoringResultAdapterRepository implements ScoringResultRepository {
  private ScoringResultJpaRepository scoringResultJpaRepository;

  ScoringResultJPARepository(ScoringResultJpaRepository scoringResultJpaRepository) {
    this.scoringResultJpaRepository= scoringResultJpaRepository;

  public void save(ScoringResultAggregate scoringResultAggregate) {
    // converts aggregate to ScoringResultEntity and saves the state into DB
  }

  public ScoringResultAggregate findByApplicationNumber(ApplicationNumber applicationNumber) {
    // loads an ScoringResultEntity from DB and converts it into an aggregate
  }
}


轴突服务器

Axon server 看起来很有前途。虽然,它只对 event sourcing 有用吗? 它可以与 Sql 存储聚合(状态持久性)并且域事件在 Axon 服务器中持久化的数据库一起使用吗?



很多问题。希望有 Axon 经验的人可以帮助我:-)

我希望我能回答其中的一些问题,但我也没有真正使用 Axon 的经验:

Return 来自命令处理程序的值 - 是的,这是可能的。我们有一个示例,其中我们 return 生成了聚合 ID(我不是 100% 确定这个答案)

本地与远程域事件发布 - 是的,Axon Server ENTERPRISE (!) 支持为此目的构建的多上下文。 https://axoniq.io/product-overview/axon-server-enterprise

CQRS 同步 - 这个问题并不完全清楚,但没有必要使用 CQRS 对整个系统进行建模。您可以对某些域使用 CQRS,对子域使用其他架构。

将 Saga 用于任何类型的 "transaction" 之类的东西。回滚应由开发人员编写。系统不能为你做这件事。

模块化单体 - 应该不是技术问题。

完全分离的域模型(与持久性无关) - 问题不完全清楚,但仅在 Axon 服务器中存储事件。聚合体是由一系列聚合体组成的。不要为此使用任何其他数据。聚合用于通过状态检查执行命令处理并应用新事件。

如果系统收到命令消息,Axon Framework 将查看聚合 ID 并通过重播该聚合的所有现有事件来重新创建聚合。然后在具有系统状态的聚合上调用@CommandHandler 和命令消息类型的方法。不要自己做这件事。

另一方面。通过侦听事件 (@EventHandler) 创建自己的自定义投影(视图模型),并将数据以您自己的格式存储到任何类型的数据 models/repository。例如,您可以在此基础上构建 REST api 以使用数据。

Axon 服务器 - 在其构建的地方使用它。将其用作事件存储而不用于其他目的。

查看更多信息和原因:https://www.youtube.com/watch?v=zUSWsJteRfw

我觉得 Jasper 说的是对的,但我也觉得我可以再强调一下:

  • 命令处理 - 是的,您可以在命令处理程序上设置 return 值。请注意,不要将此滥用到用户的 return 状态,因为这会将命令模型(处理命令的聚合)与查询模型混合在一起。

  • 本地与远程域事件发布 - Jasper 清楚地说明了这一点,他是对的。您满足了形成有界上下文的愿望,Axon Server (Enterprise) 对此提供了支持。如果您不使用 Axon,则必须自己构建此基础架构。

  • CQRS 同步 - Axon 为异步和同步消息传递提供了很好的句柄。主要区别在于您将阻止发送消息的结果。例如 CommandGateway 有一个 sendsendAndWait 方法,从而为您提供同步和异步命令调度。最后,在不进行事件溯源的情况下使用 Axon Server 作为事件存储是完全没问题的。事件溯源是使用 Axon 时的一种选择,而不是必需的。

  • 模块化单体 - AxonIQ 作为一家公司积极鼓励这种构建软件的方法。所以是的,你可以这样做,不,我想不出你在这样做之前应该想到的任何事情。

  • 完全分离的域模型(与持久性无关) - 从您的查询模型中,您可以完全控制您希望如何将数据模型映射到和来自您使用的实际模型。 Axon 术语中的聚合应被视为您的命令模型,您可以为其选择事件源存储方法或状态存储存储方法。 Axon Framework 提供的状态存储实现基于 JPA,因此需要您在命令模型中的 axon 注释旁边设置一些注释。如果您需要将其分开,我可以想象您会创建自己的 RepositoryAggregateFactory 变体。再一次,事件溯源方法将使您的域模型完全清除持久性注释,所以老实说,我会选择这条路线。

  • Axon Server - 是的,即使您采用聚合的状态存储方法,也可以使用 Axon Server。知道 Axon Server 除了作为事件存储之外,还是一个用于命令、事件和查询的统一路由解决方案。如果您要从模块化整体式架构迁移到(微)服务设置,使用 Axon 服务器来执行所有消息路由将使您的生活变得非常非常轻松。