如何在春季靴子的不同位置自动连接Singleton bean

时间:2018-09-26 21:35:12

标签: java spring-boot

在这一点上,我很困惑,根据我的理解,我是否知道所有spring boot应用程序bean都是单例的,如果我们用@Service注释的类将bean @Autowired限制为一个类(如果我错了,请纠正我),这是可以正常工作的代码,但是我试图了解它的工作原理?一个豆如何在两个不同的类中@Autowired

如何一次在SampleService@Autowired中将SampleController2 bean变成SampleController3

这是推荐的方法吗?在这种情况下,两个线程可以并行更改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");
    }
 }

3 个答案:

答案 0 :(得分:2)

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

事实上,这就是他们的全部重点。

这也意味着两个不同的线程确实可以更改同一bean的状态。出于这种原因,您通常会希望使bean保持无状态。

如果您确实需要在每个自动装配的地方都具有一个不同的bean实例,则可以将该bean的范围更改为prototype。参见Spring bean scopes docs

答案 1 :(得分: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被添加到存储库中,因此您可以按名称查找它们,也可以在以后的任何时间键入它们。

答案 2 :(得分:0)

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

  • 您一次定义您的注射剂(如服务),并且实例化一次(除非您另外指定)。
  • 然后在所有适用的地方使用这些注射剂,而您无法控制其生命周期,作用域或状态。

虽然我觉得最后一点相当隐性地回答了您的主要问题,但我会详细说明-在直接投资背景下,唯一真正重要的是可强制执行的合同。也就是说,如果您的服务订阅了特定类型的合同,并且您有一个组件希望注入能够履行该合同的服务,那么您的DI层应该如实地注册一个可以履行该合同的服务。

在那时,您将获得有关bean优先级,限定符和应用程序配置文件的有趣有趣的内容,但这是一般的想法。

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

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

  

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

创建具有自身固有状态的可注入bean是 非常 的明智做法。也就是说,如果您将SampleService自身附加到某种内部具有集合的缓存状态,则基本上是在违反期望,因为您不知道该集合何时或多长时间添加一次元素或从中删除。

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