java - 为什么我需要一个存储库和一个服务+契约(Contract)

标签 java spring spring-data kotlin dao

我是来自 PHP/Larvel、Ruby/Rails 和 Python/Django 的 Spring 新手。来自这些框架,我习惯于只看到模型(Entity/Dao?),其他一切都由 Framework/ORM/QueryBuilders 处理,因此我要做的就是声明一个模型并向其添加任何操作/我需要的关系/方法。

在这些框架中,这就是我所拥有的:

class User extends BaseModel
{
  public function devices() { .. } // Relation to Device model

  // Any additional functions on user go here these can operate on 
  // just the User model or pull additional data from DB or other models.  
  public function assignUserToDevice();
  public function getUsersScore();
  public function connectUserToService();
}

但是,在这个 Spring 教程之后,我现在有了这个:

模型(Entity/Dao?):仅包含属性,除 GET/SET 和关系外不包含任何方法。

@Entity  
@Table(name = "users")  
class User {
  @Id
  @GeneratedValue  
  var id: Long = 0

  var username: String = "" //...
}

存储库:

interface UserRepository : CrudRepository<User, Long> {
  fun findByUsername(username: String): User
}

用户服务合约:

interface UserServiceContract {

    /**
     * Attempts to find User associated with the given id.
     * @throws ModelNotFoundException if not user has been found associated with the given id.
     * @param id given users id.
     * @return User associated with the given id.
     */
    @Throws(ModelNotFoundException::class)
    fun find(id: Long): User

    /**
     * Returns all existing users.
     * @return list of all existing users.
     */
    fun findAll(): List<User>
}  

还有一项服务:

@Service
class UserService : UserServiceContract {

    @Autowired
    lateinit var userRepository: UserRepository

    /**
     * Attempts to find User associated with the given id.
     * @throws ModelNotFoundException if not user has been found associated with the given id.
     * @param id given users id.
     * @return User associated with the given id.
     */
    override fun find(id: Long) = userRepository.findOne(id) ?: throw ModelNotFoundException("User not found!")

    override fun findAll(): List<User> {
        throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}  

问题:

  1. 为什么我需要 UserRepositoryUserService + UserServiceContract ?从我在存储库上的 Spring 指南中读到的内容中,您已经获得了默认的 CRUD 方法保存、读取、更新、删除.. 除此之外,您还可以使用查询方法可以执行 findUserBy... 或编写带注释的原始查询。所以我有点困惑为什么不声明 UserServiceContractUserService 只是为了实现存储库已提供的功能?

  2. 以前,我会在所述模型中保留用于处理我的模型的方法,但是正如我从很少的资源中注意到的那样,这不是它们在 Spring 中的位置,那么我应该将它们保留在哪里?这就是为什么有 UserServiceUserServiceContract 吗? 我是否真的应该仅使用 UserRepository 进行数据库访问,并在 UserServiceContract 中声明用于处理/与用户一起工作的方法,例如:public function connectUserToService() ?

最佳答案

用户是实体。它基本上代表数据库中表中的一行。而且它绝对可以有方法。将与该实体无关的方法仅放在实体类中通常不是一个好主意。特别是不需要访问外部依赖项(例如存储库或服务)的方法。

存储库是允许执行与给定实体相关的查询或保存该实体的新实例的组件。

服务包含业务逻辑。它可以像简单地委托(delegate)给存储库一样简单,但除非您的应用程序仅用于查看数据库中的信息,否则它通常包含更复杂的逻辑,涉及多个实体和存储库。

将存储库与服务分离很有用,因为它允许

  • 避免混合责任,
  • 轻松测试查询,无需使用它们调用复杂的逻辑
  • 通过模拟存储库轻松高效地测试业务逻辑
  • 划分事务边界:服务方法通常是一个事务。

是否使用接口(interface)来定义服务契约取决于您。 Spring 不会强制你这样做。如果你想搬起石头砸自己的脚,你也可以混合服务和存储库,但 Spring 不鼓励这样做,如果你使用 spring-data-jpa,你将无法做到这一点,它基本上会生成一个基于接口(interface)为您实现存储库。

我对您习惯的框架了解不多,但是在考虑 Spring 应用程序的设计时,您需要记住这一点:Spring 是一个依赖注入(inject)框架,因此它包括将组件注入(inject)到其他组件。实体不是 Spring 组件,因此如果它们包含业务逻辑(这又会混合职责,IMO),则无法注入(inject)它们所需的依赖项。而依赖注入(inject)本身主要是用来让代码 可测试,并且能够围绕方法调用添加方面(例如,启动和提交事务)。这就是 Spring 设计的驱动力:单一职责原则、依赖注入(inject)带来的可测试性,以及。

关于java - 为什么我需要一个存储库和一个服务+契约(Contract),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42747132/

相关文章:

mysql - Spring Hibernate MySQL 测试不回滚

java - 保存然后更新 Spring Data 中的实体

java - mongo模板findAndModify返回列表

java - 具有多个条件的 for 循环的大 O

使用 XML 请求 URL 的 Java 正则表达式

java - Hibernate,对用户类型的简单依赖注入(inject)

java - @service 在 spring 中的混淆行为

java - 在 Eclipse 中找不到 JDBC 驱动程序,但在独立运行时找到

java - Spring Boot 测试服务(使用带有 JDBCTemplate 的存储库)

hibernate - 如何在 Spring Data JPA 中使用多个 JPA 持久性上下文?