【问题标题】:How Singleton bean can be Autowired in different places spring bootSingleton bean如何在不同的地方自动装配spring boot
【发布时间】:2018-09-26 21:35:12
【问题描述】:

此时我很困惑,我知道所有 Spring Boot 应用程序 bean 都是单例的,根据我的理解,如果我们有使用 @Service 注释的类,那么 bean 只能在一个类中是 @Autowired(纠正我如果我错了)这里的代码可以正常工作,但我想了解它是如何工作的?一个 bean 如何在两个不同的类中成为@Autowired

SampleService bean 如何同时在 SampleController2SampleController3 中成为 @Autowired

这是推荐的方法吗?在这种情况下,两个线程可以并行更改 bean 内的数据?

SampleController2

@RestController
@RequestMapping(value="samplemock")
public class SampleController2 {

@Autowired
private SampleService2 sampleservice2;

@RequestMapping(value="/mock1",method=RequestMethod.GET)
public void mockCall1() {
    sampleservice2.m1();
   }

}

SampleController3

@RestController
@RequestMapping(value="samplemock2")
public class SampleController3 {

@Autowired
private SampleService2 sampleservice2;

@RequestMapping(value="/mock1",method=RequestMethod.GET)
public void mockCall1() {
    sampleservice2.m1();

   }
 }

SampleService2

@Service
 public class SampleService2 {

public void m1() {
    System.out.println("bean is autowired");
    }
 }

【问题讨论】:

  • 要理解这一点,您必须了解依赖注入。依赖注入是关键字 Autowired 背后的概念。换句话说,两个控制器中的 sampleService2 变量都是简单的声明,这意味着没有关联的实例对象。请记住,Spring 核心负责在需要时单独创建实例。
  • 我经历了依赖注入,你的意思是它会创建两个实例?还是单个实例?
  • 单例并不意味着它只能在一个地方使用。您可以在两个不同的地方使用相同的实例
  • 肯定会创建两个实例,因为这些bean不一定同时被调用。
  • @Solace,你能给我更多信息吗?单例 bean 如何在不同的地方自动装配?只是我想简单解释一下,有一个单例 bean,它与 controller1 中的引用相关联,同样的 bean 如何与 controller2 引用相关联?

标签: java spring-boot


【解决方案1】:

这是 Spring 在启动时所做的简化视图:

// Create bean: sampleService2
SampleService2 sampleService2 = new SampleService2();

// Create bean: sampleController2
SampleController2 sampleController2 = new SampleController2();
sampleController2.sampleservice2 = sampleService2; // because @Autowired

// Create bean: sampleController3
SampleController3 sampleController3 = new SampleController3();
sampleController3.sampleservice2 = sampleService2; // because @Autowired

如您所见,单例 bean sampleService2 自动装配到 sampleController2sampleController3

bean 被添加到存储库中,因此您可以在以后的任何时间按名称或类型查找它们。

【讨论】:

  • 非常感谢@Andreas 提供的宝贵信息,我还有一个问题,根据我的理解,当 spring 容器启动时,它会创建 bean 并保存一个副本(单例),所以当请求来操作将在 bean 上执行并保存更新的副本,对吗?如果一次有两个线程请求 bean 怎么办?一个线程 bean 更新如何反映到另一个线程?
  • @Deadpool 大多数单例 bean 是无状态的,即在设置后它们是不可变的。 Web 请求由控制器(和服务)处理,但 bean 本身不会更新。 --- 另外,"save back the updated copy" 意味着多个实例,这违反了 singleton 方面。所有请求都由单个实例并行处理,但由于该实例是无状态的,因此不存在多线程问题。
  • 谢谢@Andres,如果我错了,请纠正我,spring bean 是单例和不可变的,但是 bean 内部的属性可以由多个线程更新,这是开发人员的责任,所以在这个如果一个线程更新该 bean 的某个实例属性而第二个线程当时正在请求 bean,会发生什么情况?
  • @Deadpool 你错了。 Spring bean 不可变意味着它们不会更新 bean 的字段,因为如果它们更新了,它们就不是不可变的。由于大多数单例 bean 旨在并行处理 Web 请求,因此它们应该始终是无状态的,即不可变的,以确保它们始终是线程安全的。 --- “第二个线程是请求 bean”是什么意思?通常,所有 bean 都自动连接在一起,因此在启动时连接,因此在请求时没有“请求”bean,因为它们已经可以相互访问。
  • 非常感谢@Andreas,我想我对stateless and stateful`感到困惑,但我现在明白了,谢谢你
【解决方案2】:

默认情况下,正如您所提到的,所有 Spring bean 都是单例的,但您的第二个假设是错误的:同一个 bean 可以在许多其他 bean 中自动装配。

事实上,这就是他们成为单身人士的全部意义所在。

这也意味着两个不同的线程确实可以改变同一个 bean 的状态。出于这个原因,您大多数时候都希望让您的 bean 保持无状态。

如果您确实需要为每个自动装配的位置拥有一个不同的 bean 实例,您可以将该 bean 的范围更改为 prototype。见Spring bean scopes docs

【讨论】:

  • 你的意思是原型?你能举个例子或链接吗?所以我可以在哪里获得更多信息
  • 你能给我更多的信息吗?单例 bean 如何在不同的地方自动装配?只是我想简单解释一下,有一个单例 bean,它与 controller1 中的引用相关联,同样的 bean 如何与 controller2 引用相关联?
【解决方案3】:

依赖注入和控制反转背后的意图很简单:

  • 您定义了您的可注入对象(如服务)一次,并且它们实例化一次(除非您另有说明)。
  • 这些注射剂随后在任何适用的地方使用,您无法控制它们的生命周期、范围或状态。

虽然我觉得最后一点相当默契地回答了您的主要问题,但我会详细说明 - 在 DI 上下文中,唯一真正重要的是可执行合同。也就是说,如果你的服务订阅了特定类型的合约,并且你有一个组件希望注入一个满足该合约的服务,那么你的 DI 层应该忠实地注册一个可以满足该合约的服务。

此时,您会通过 bean 优先级、限定符和应用程序配置文件获得有趣和令人兴奋的东西,但这是大体思路。

举个具体的例子:javax.sql.DataSource 是一个由许多 JDBC 支持的解决方案实现的接口,例如 MySQL、Postgres、Oracle 等。如果您希望有两个不同的 bean 与两个不同的数据库通信,但您希望能够互换使用它们,那么您定义一个 DataSource 类型的 bean 来使用和配置 which 数据源被创建。同样,这确实涉及 @Qualifier 之类的东西,以确保您在最合适的时间连接到最具体的 bean。

此外,最后一点对于回答您的这部分问题非常重要:

...在这种情况下,两个线程可以并行更改 bean 内的数据?

非常创建一个具有自身固有状态的可注入 bean 是不明智的。也就是说,如果您将 SampleService 附加到某种缓存状态,其中包含一个集合,那么您基本上违反了预期,因为您不知道该集合何时或多久会添加元素或从中删除。

更好的约定是让 bean 可以引用有状态服务,但不要将该状态存储在 bean 本身中(例如数据库连接,但不是整个数据库表)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-03
    • 1970-01-01
    相关资源
    最近更新 更多