如何从spring数据代码中清晰地(物理地)分离域层?

时间:2015-12-09 20:53:41

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

在我的DDD-by-the-book应用程序中,我在域层中有一个这样的存储库定义:

public interface CustomerRepository {
    Customer findById(long id);
    ...
}

数据库集成层包含此接口的实现,如下所示:

public class CustomerDao implements CustomerRepository {
    public Customer findById(long id) {
        // access EntityManager or JDBCTemplates or ...
    }
}

每个层都有一个模块,数据库模块依赖于域和所有集成库(例如hibernate),而域模块依赖于任何东西。因此,我们对问题进行了清晰的分离,而且没有“技术”问题。 DDD提出的域的依赖性。因此,我可以通过创建适当的存储库实现从数据库切换到内存中持久性。使用的实现在我的应用程序层中配置。

实现数据库访问的存储库非常糟糕,因为我们有Spring Data,所以不再需要了。要使用spring数据,我必须定义一个这样的存储库。

public interface CustomerRepository implements Repository<Customer, Long> {
    ....

这意味着,由于存储库接口定义在我的域层中,我现在将我的域层依赖于&#34;技术&#34;图书馆。切换到内存中实现时,我的应用程序中也会有spring-data类。我想,这有点味道。

你怎么看待它?你怎么处理这个?是否可以使用spring数据并且没有来自我的域图层的依赖项?

THX

(顺便说一句:我的业务对象是JPA注释的,因此我的域模块依赖于javax.persistence。但我可以忍受这个,主要是因为javax.persistence只包含注释而没有实现。所以这是一个& #34;逻辑&#34;而不是&#34;技术&#34;依赖。我认为对spring-data-annotation模块的依赖会闻起来更少。)

2 个答案:

答案 0 :(得分:6)

最近,在使用Spring Data进行项目并遵循Onion架构时,我遇到了同样的挑战。以下是我的食谱:

  1. 定义CustomerRepository(在您的域层中),而不引用Spring Data:

    public interface CustomerRepository {
      Customer findById(long id);
      // ..
    }
    
  2. 在您的数据访问层中定义CustomerDao,它依赖于Spring Data:

    public CustomerDao implements Repository<Customer, Long> { }
    
  3. 定义域CustomerRepository的实现,它将所有调用委托给CustomerSpringDataRepository,并且会有一个由Spring注入的CustomerDao实例:

    public class CustomerRepositoryImpl implements CustomerRepository {
       @Autowired private CustomerDao dao;
    
       public Customer findById(long id) { return doa.findById(id); }
    }
    
  4. 在您的域图层中注入CustomerRepository

  5. 采用这种方法:

    • 您的域层没有对Spring Data的依赖,只有数据访问层依赖于Spring Data
    • 您的域不依赖于数据访问层,这意味着域中不会显示任何基础结构(如Spring Data)

    我按照上述方法创建了a sample project using Spring Data and the Onion architecture

答案 1 :(得分:1)

将Spring Data存储库注入您的域存储库,然后您的域存储库接口将不依赖于&#34;技术&#34;图书馆了。

public interface CustomerSprignDataRepository implements Repository<Customer, Long> {

}
public class CustomerDao implements CustomerRepository {

      @Inject
      private CustomerSprignDataRepository customerSprignDataRepository;

      public Customer findById(long id) {
          // access EntityManager or JDBCTemplates or Spring Data Repository
      }
}