具有 spring 数据的六边形架构

hexagonal architecture with spring data

我要开始一个新项目来学习spring引导、spring数据和六边形架构。根据我的理解,六边形架构旨在将核心或域层与数据库操作(基础设施层)分开。我看到了这个架构的以下项目结构。

核心层有:

服务->逻辑去向(接口及其实现)。

实体 -> 这些将在整个应用程序中使用。

Repository->基础设施层必须实现的接口。

基础设施层实现了存储库接口、JPA 实体、对数据库的调用(休眠)以及将 JPA 实体转换为核心实体(映射器?)的某种功能。

Spring数据有一个非常有用的实现CRUD操作的方法:

public interface UserRepository extends JpaRepository<User, Integer> {
}

但是,我认为如果我使用 spring 数据,如果 UserRepository 是核心层的一部分,那么 JPA 实体将不会成为基础结构层的一部分。这意味着核心实体将毫无用处。我应该创建另一个属于核心层的 UserRepository 接口还是我遗漏了什么?

更新:

我对使用 spring 数据的担忧来自于我必须在域内包含 JPA 实体,这在理论上会违反六边形体系结构。

所以我想将域实体与 JPA 实体分开。但是如果我这样做,我不知道 Spring 数据的存储库应该去哪里,也不知道将 JPA 实体转换为域实体的方法。

为了更好地说明,我假设我需要从我的应用程序连接到数据库以读取用户 table。

这可能是域实体:

public class UserDomain{
  private String name;
  ....//More fields, getters, and setters.

根据我的理解,服务应该包括逻辑和操作域实体。

public interface UserService{
  public void create(UserDomain user);
  ...

实施:

public class UserServiceImpl implements UserService{
  public void create(UserDomain user) {
     ... //Calling the repository(Spring Data Repository?)

以上以及存储库界面是我认为的域(如果我错了请纠正我)。接下来,基础设施由 JPA 实体组成

@Entity
@Table(name="users")
public class User{
  @Column(name="name")
  private String name;
  ... // More Fields, getters, and setters

我认为调用 Spring 数据的接口应该在基础结构部分,因为稍后我需要将 JPA 实体映射到域实体中,也许我需要使用另一个 class(和适配器?)来做那个映射。这种方法是正确的还是有其他方法?抱歉了这么久post,希望我说清楚了。

我对你的问题有点困惑。您经常谈论层,而我认为 "the article" 六边形架构使用该术语(几乎?)专门用于描述不该做的事情。

Spring 数据非常适合六边形方法:实体构成您的核心域,存储库接口构成面向 API 的数据库。请注意,实现(在核心域之外,主要由 Spring Data 本身提供)取决于接口,而不是相反)。服务 and/or 控制器形成一个或多个面向用户的 APIs.

有一些违反六边形架构规定的规则的地方:实体和存储库上的注释。它们位于核心域内,但通过成为 JPA 或 Spring Data.Spring 的一部分,依赖于数据库访问的 usage/implementation。

JPA 本身甚至进一步违反了六边形架构,因为持久性实现的行为可能会严重泄漏到您的域中,因为如果您使用托管实体,任何更改都会被自动跟踪并最终持久化,而无需调用持久性 API。此外,对持久层的更改(如刷新策略的配置)可能会完全改变 API.

的行为

这是一篇关于如何将数据库连接到应用程序的好文章:http://www.dossier-andreas.net/software_architecture/ports_and_adapters.html

您要做的是创建“辅助端口”和“辅助适配器”。

'secondary port'(=接口)描述了要做什么,但没有框架依赖性。 'secondary adapter'(= 实现)使用 jpa-repositories。

jpa 实体不能是您的域。它描述了数据如何存储在数据库中。所以 jpa-entity 不能在 'secondary port' 中使用,只能在你的域中使用。

'secondary adapter' 需要将您的域转换为 jpa-entities。

但是,如果您真的想使用正确的 六边形结构,请小心。 Hibernate 和后来的 JPA 的强大之处在于 jpa-entity 是您的域。它使事情变得更简单(也更难)。通过将您的域与您的实体分开,您将失去延迟加载的机会、清晰的事务边界、孤立删除……也许您应该权衡并将 jpa 放在核心层中。

希望本文对您有所帮助

为了添加到 Tom 的回答中,我发现了以下选项:

  • 使用在 spring 数据中完成的相同构造创建一个接口,问题是您必须在服务中进行转换。
  • 创建一个抽象 class,其中包含未定义的函数,可以为您提供数据,然后在 spring 服务中,继承该 class 并使用 jpa 存储库实现这些函数,问题是您不会将您的存储库与您的服务分开。
  • 不要为存储库创建接口,在域中创建一个 class / 接口来为您提供数据(这将是您的存储库),该功能是您在 spring 将有存储库的图形但没有注释,如果您使用 JPA 存储库,例如。

Domain.Service 使用 Domain.RepositoryApplication.repository 继承自 Domain.repository 并使用 JPA Repository,Aplication.service 继承自 Domain.service 并使用 Domain.repository

前一个的问题是为应用程序服务注入 spring 的依赖项的复杂性和玩法

另一个问题是实体,有的项目我直接用jpa,有的项目只用getter和setter做接口,后者有点麻烦