如何使用Spring Crud / Jpa Repository实现DDD

时间:2018-04-20 05:57:24

标签: spring spring-data spring-data-jpa domain-driven-design ddd-repositories

我想通过使用Spring实现DDD来创建应用程序。假设我有一个业务实体Customer和一个CustomerRepository接口。

由于spring提供CrudRepositoryJpaRepository来执行基本的CRUD操作以及其他操作(如finder方法),我希望使用它们。所以我的界面变成了

 @Repository
public interface CustomerRepository extends JpaRepository<Customer, Long>{

}

但是根据DDD,接口应该在域层中,并且实现应该在Infrastructure层中。

现在我的问题是,CustomerRepository属于哪个层?

1 个答案:

答案 0 :(得分:3)

简答:虽然它应该是域层中基础架构的任何依赖项,但为了KISS,您可以这样做。如果您想成为DDD纯粹主义者,请在基础架构中定义CustomerRepository接口和实现两个接口的实现。

漫长而无聊的回答:一般情况下,域名不应该关心或了解基础架构,因为它不应该依赖于其他层(基础架构,应用程序,演示文稿或任何架构)使用)。遵循此规则可以实现更清晰的架构。

特别是,域不应该关心持久性,它应该在内存中运行时表现。从Domain点来看,实体变异,就是这样,不需要持久性。

域代码的写入端实际上不需要持久性。当Aggregates执行命令时,它们已经完全加载。执行命令后,Aggregates只返回更改或新状态。聚合不会自己保留更改。它们是纯净的,没有可观察到的副作用。

我们架构师需要持久性,因为我们需要确保数据在重新启动之间保持不变,并且我们可以在同一时间在多台机器上运行相同的代码。

然而,还需要域代码,特别是域的读取和反应端(Sagas /流程管理器)。域的这些组件需要查询和过滤域实体。 Readmodels需要将实体返回给调用者,并且Sagas / Process管理器需要正确识别要向其发送命令的正确聚合。

解决方案是仅定义域层中的接口并在基础架构中实现。通过这种方式,域拥有接口,因此根据Dependency Inversion Principle,它不依赖于基础设施。

在您的情况下,尽管Domain层依赖于Spring Framework的Infrastructure部分中的某些,但某些只是一个接口。它仍然是JPA的依赖项,因为您的域将使用它不拥有的方法,但在这种情况下KISS可能更重要。

另一种方法是定义一个不扩展JpaRepository的接口,其中包含实现此接口和JpaRepository接口的基础结构中的实现。

哪种解决方案取决于您:更多的代码重复但更少的依赖性或更少的代码重复以及对JPA的更多依赖。