【问题标题】:Spring @Repository best practicesSpring @Repository 最佳实践
【发布时间】:2015-03-18 08:38:23
【问题描述】:

上下文:Web 应用程序

我以前没有使用过 Spring,但是根据 Spring 文档,所有的 bean 都是 singleton,除非我们将它们声明为 prototype

  • 不使用 Spring:

通常我会在调用业务/服务层时实例化新的 DAO。 如果是 RESTfull 服务,我会实例化几乎所有依赖于调用的对象。

  • 带弹簧:

我可以使用@Repository 注释数据访问类,也可以将@Service 用于服务层类。

所以我的带有上述注释的类默认为singleton。 有一个 @Scope 注释,我们可以将它们声明为原型,但似乎没有人这样做

  • 没有弹簧:new Object(); 每次
  • 带弹簧:singleton

我的问题是,

  1. 我之前使用的方式(每次创建新实例)不正确?
  2. 如果@Repositorysingleton,如果没有解决这样的问题,它如何处理线程安全? (假设它是由 spring 代理完成的)
  3. 什么是最佳实践, @Repository 就够了,还是加上@Scope('prototype') 会更好?
  4. 我没有看到有人使用@Scope('prototype')@Repository(根据教程、博客等)。有什么众所周知的原因吗?
  5. 如果我的 DAO 类被多个非常高频率的大量线程访问怎么办? (这是我最关心的)

谢谢

【问题讨论】:

    标签: java multithreading spring spring-mvc


    【解决方案1】:

    使用 @Repository 注释的组件应该是单例的,因为它在其整个生命周期中永远不会有多个/不同的状态。是的,它可以保持的唯一状态是连接对象,它只会在对象创建期间设置一次。并且它将包含与数据存储对话的逻辑/方法,每个方法将获取/返回所需的数据对象。因此不需要有多个存储库实例。

    【讨论】:

      【解决方案2】:

      你说得对——在 Spring 世界中,大多数 bean 都是单例的。

      1. 我之前使用的方式(每次创建新实例)不正确?

      这不是错误的,因为它有效。关于它的问题是你在每个请求上都实例化一个新的 DAO 实例——在某些情况下它可能很昂贵,而且无论如何它没有任何意义——你为什么需要一堆 DAO 实例? 另一方面,Spring 不仅创建了一个单例,而且还将 DAO 注入到服务或其他 DAO 等。即为你做了很多工作

      1. 如果@Repository 是单例的,那么当没有解决这样的问题时,它如何处理线程安全? (假设它是由 spring 代理完成的)

      当你编写一个@Repository bean 时,你通常会在那里注入一个DataSource 或一个EntityManager。 DataSource.getConnection() 方法应该是线程安全的。对于 EntityManagerSpring 将注入一个代理,该代理对于不同的线程表现不同,即不同的线程不会共享同一个 JPA 会话。

      1. 最佳实践是什么,@Repository 就足够了,还是添加 @Scope('prototype') 会更好?

      最佳实践(或者说是最广泛使用的方法)是只使用@Repository

      1. 我没有看到有人将@Scope('prototype') 与@Repository 一起使用(根据教程、博客等)。有什么众所周知的原因吗?

      原因是创建多个@Repository bean 实例没有任何好处

      1. 如果我的 DAO 类被多个非常高频率的大量线程访问怎么办? (这是我最关心的)

      这里再次强调单例比为每个请求创建一个新对象要好。避免冗余同步,这样您的线程就不会在某些监视器上阻塞

      【讨论】:

      • 非常感谢您的明确回答。 “避免冗余同步”到底是什么意思?我的 DAO 没有定义任何同步方法或块。
      【解决方案3】:

      Spring 不会为您处理并发问题。这并不意味着。它所做的只是让您控制创建实例的数量,以便您的应用程序可以正常工作。

      单例范围(很明显)将只创建给定 bean 的一个实例并将其传递给所有依赖对象。

      每个依赖对象的原型范围都将创建自己的实例,而不是在其他对象之间共享。

      对于 DAO 对象,您不太可能需要多个实例来与数据库通信。所以大多数情况下总是使用单例。

      【讨论】:

        【解决方案4】:
        1. 不,但是单元测试要困难得多,这就是依赖注入的全部意义所在。通过在服务中注入 DAO,您可以通过在测试期间注入模拟 DAO 轻松地对服务进行单元测试。如果服务创建自己的 DAO,这是不可能的。

        2. 存储库通常是完全无状态的,除了在启动时初始化的线程安全实体管理器、会话工厂或 JDBC 模板,因此并发调用不是问题:它是线程安全的。

        3. 存储库没有理由成为原型。将原型 DAO 注入单例服务仍然会导致同时调用每个原型。

        4. 没有理由这样做。

        5. 没问题:如果编码正确,它应该是线程安全的。

        【讨论】:

          猜你喜欢
          • 2015-09-11
          • 2020-03-08
          • 2010-12-22
          • 1970-01-01
          • 2015-04-19
          • 2010-11-07
          • 2011-05-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多