【问题标题】:Is it ok to expose JpaRepository in Spring to clients?可以将 Spring 中的 JpaRepository 暴露给客户吗?
【发布时间】:2012-12-09 21:48:08
【问题描述】:

我有一个关于在 Spring 中使用 JpaRepository 的概念性 OO 问题。是否可以将 JpaRepository 暴露给调用者并让他们在该实例上调用 CRUD 方法,或者我必须包装每个方法并仅从服务中调用相应的 JpaRepository 方法?

在代码中:

public interface MyJpa extends JpaRepository<MyEntity, Long>

然后:

@Repository
public class MyDbService{

    @Autowired
    private MyJpa myJpa;

    public Iterable<MyEntity> findAll()
    {
        return myJpa.findAll()
    }

    ... other CRUD methods

}

然后客户会这样做:

Iterable<MyEntity> entities = myDbService.findAll();

相对于:

@Repository
public class MyDbService{

    @Autowired
    private MyJpa myJpa;

    public MyJpa getJpa() {
        return myJpa 
    };
}

然后客户会这样做:

Iterable<MyEntity> entities = myDbService.getJpa().findAll();

不使用第二种方法的主要问题是什么?

【问题讨论】:

    标签: java spring jpa spring-data spring-data-jpa


    【解决方案1】:

    我更喜欢后一种方法。在我处理的应用程序中,我通常有以下层(可能有更多或更少的层 - 这是一个非常粗略的指南):

    第 1 层 - 客户端层

    也许是 Spring MVC @Controller@Service。例如:

    @Controller
    public class MyController {
      @Autowired private MyManager myManager; // see Layer 2
    }
    

    第 2 层 - 业务层

    第 2 层提供了客户端层和 DAO 之间的分离。它通常是超过 1 个或多个 DAO 的外观。你可以把业务逻辑/规则放在这里,或者委托,或者添加另一个层。例如:

    @Component
    public class MyManagerImpl implements MyManager {
      @Autowired private MyDao myDao; // see layer 3
    }
    

    第 3 层 - DAO 层

    第 3 层是您的 DAO 或 @Repository 类。根据您的示例:

    public interface MyDao extends JpaRepository<MyEntity, Long> {
      // Spring Data JPA magic here!
    }
    

    一些一般性的建议:

    • 没有严格的规定,每个应用程序都不同。根据您的应用要求做对您有意义的事情
    • 每一层应该只有一个职责。如果您发现一个层具有多种职责(例如数据访问和客户端 API),那么最好将其分成两层

    最后,我在您的示例中做的一个小改动是用@Component 而不是@Repository 注释MyDbService@Repository 应仅限于 DAO。

    希望漫无目的的说得通!

    【讨论】:

    • 感谢您的回复。是的,就层而言,我做的事情几乎相同。我的问题可能更多是关于你的图层有多不透明。即,Layer 1 是否可以调用 Layer 2 的 API,或者 Layer 1 可以从 Layer 2 获取 Layer 3 的实例然后与之交互。看起来违反这种层间隔离可能是不使用 getJpa() 方法的原因之一。
    • @DennisK 是的,我总是将第 1 层和第 3 层分开!这绝对违反了每层责任原则。有趣的是,这是我在使用 Spring 和自动装配时偶尔会遇到的一种情况。获取任何 Spring 管理的类的实例太容易了。
    【解决方案2】:

    在您的情况下,中间层已过时。如果您只是重新公开依赖项(无论如何这都是一种反模式)或发现自己除了委托给依赖项之外做任何事情,只需将依赖项注入您的客户端即可。所以例如我认为从 SpringMVC 控制器等使用存储库可能是绝对可以的。

    但是有两点需要考虑:

    1. 我们通常不建议扩展 JpaRepository,因为它公开了 JPA 特定的方法,并且客户端实际上不应该知道底层的持久性技术。所以宁可使用CrudRepositoryPagingAndSortingRepository 之类的。

    2. 绝对使用中间层,以防您需要协调多个调用,因此可能需要划定更广泛的事务边界。或者,如果您想避免客户端直接使用存储库,请将其封装在服务中的受保护和更高级别的方法中,这可能会执行额外的业务功能(例如密码编码等)

    【讨论】:

    • 谢谢,奥利弗。是的,这种方法可行,但前提是您的存储库有一个客户端。 #1 中的要点也很重要。
    • 实际上让我想到这个问题的原因是考虑组合几个相互关联的表(比如 A、B 和 C)的服务,并且除了 CRUD 之外只公开了一些特定方法,例如“get B.由 A.id 和 C.timestamp 命名”。重新映射 CRUD 方法会使这个类成为许多样板​​代码的容器。因此,让 CRUD 方法可以通过 myDbService.getACRUD()、.getBCRUD()、.getCCRUD() 访问,然后只向服务本身添加特定的复杂请求,可以使类更加简洁和可读......
    猜你喜欢
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-15
    • 2023-04-05
    • 1970-01-01
    • 2016-03-29
    相关资源
    最近更新 更多