2

我有一个关于在 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();

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

4

2 回答 2

4

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

第 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),那么最好将其分为两部分

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

希望漫谈是有道理的!

于 2012-12-09T23:42:36.347 回答
2

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

但是有两点需要考虑:

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

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

于 2012-12-10T18:51:14.717 回答