为什么我需要存储库和服务+合同

时间:2017-03-12 12:01:12

标签: 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();
}

然而,按照本春季教程,我现在有了这个:

Model(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
}

UserServiceContract:

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方法save, read, update, delete..,您还可以使用查询方法来执行findUserBy...或编写带注释的原始查询。所以我有点困惑为什么只声明UserServiceContractUserService来实现存储库已经提供的功能?

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

1 个答案:

答案 0 :(得分:1)

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

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

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

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

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

您是否使用界面来定义服务合同取决于您。 Spring并没有强迫你这样做。你也可以混合使用服务和存储库,如果你想用脚射击自己,但Spring不鼓励它,如果你使用spring-data-jpa,你将无法做到这一点,它基本上会生成一个基于接口的存储库实现。

我对你习惯的框架了解不多,但是在考虑spring应用程序的设计时需要牢记这一点:Spring是一个依赖注入框架,因此包含将组件注入其他组件。实体不是Spring组件,因此如果它们包含业务逻辑(再次混合职责,IMO),则不能注入它们所需的依赖项。依赖注入本身主要用于制作代码 可测试的,并且能够添加方法调用的方面(例如,启动和提交事务)。这就是驱动Spring设计的原因:单一责任原则,依赖注入的可测试性,以及。

相关问题