带有Spring的DDD Java-存储库返回Mono / Flux

时间:2019-06-04 19:26:23

标签: java spring mongodb domain-driven-design project-reactor

我想知道在使用Java和Spring Boot实现的DDD项目中实现反应性Mongo存储库时遇到的一个问题。假设我们有这样的包结构:

/app 
  |
  |------/application
  |        | 
  |        |------/order
  |                 |
  |                 |------OrderApplicationService.java
  |
  |------/domain
  |        |
  |        |------/order
  |                 |
  |                 |------Order.java
  |                 |------OrderRepository.java 
  |
  |------/infrastructure
           |
           |------/mongo
                    |
                    |------MongoOrderRepository.java

我的OrderRepository.java我想要一种保存订单的方法:

public interface OrderRepository {

    Order save(Order order);
}

并在我的应用程序服务中使用它:

@Service
public class OrderApplicationService {

    private final OrderRepository orderRepository;

    public OrderApplicationService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    public void createOrder() {
        //Dumb order creation
        Order createdOrder = clientRepository.save(new Order());
    }
}

接下来,我要编写实现OrderRepository的MongoOrderRepository。假设我将使用ReactiveMongoTemplate。问题在于它的所有方法都返回Flux或Mono,因此我无法从OrderRepository接口实现我的方法。

我看到的可能解决方案是:

  1. 在OrderRepository中使'save'方法返回的订单由 单声道这种方法将使用Reactor污染域层 特定类型并违反规则,即域层应为 免费的框架代码。
  2. 开发某种包装层,但这会产生一些 样板代码。
  3. 将OrderService.java移动到基础结构层,但这也会破坏一些基本的DDD概念。

有人看到更好的解决方案了吗?

1 个答案:

答案 0 :(得分:1)

该存储库应该与框架代码无关,这是对的,这是一个好习惯,但是您也需要务实,我有一个使用Java lambda的存储库,这是人们可以争论的语言级别框架。

使用Flux或Mono的好处是什么,将它们作为界面的一部分进行广告有什么好处?如果没有,则可以将实现细节保留在存储库实现中,并使接口没有反应性对象。

但是,如果这需要跨越应用程序层到端口适配器,那么我看不到将它们放入存储库的接口定义中的任何问题。

话虽这么说,您可能想检查另一种方法,借助CQRS和六角结构,您可以兼得两者:

  • 为命令(“更新和创建”部分)具有干净的存储库界面
  • 使用查询服务(如果在Java中为纯POJO,在应用程序包中定义),则为查询返回Mono或Flux(阅读部分)

    OrderApplicationService.java(通过命令创建更新删除) OrderQueryService.java(在此处为阅读部分)

您的应用程序服务包含对您的OrderRepository的引用,查询服务不使用该存储库,因为它通过例如ReactiveMongoTemplate更直接地查询数据库。

例如,在查询服务中,我在存储库实现中使用Hibernate时使用了普通的JDBC模板。