在这一点上,我很困惑,根据我的理解,我是否知道所有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");
}
}
答案 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
被自动连接到sampleController2
和sampleController3
中。
bean被添加到存储库中,因此您可以按名称查找它们,也可以在以后的任何时间键入它们。
答案 2 :(得分:0)
依赖注入和控制反转的意图很简单:
虽然我觉得最后一点相当隐性地回答了您的主要问题,但我会详细说明-在直接投资背景下,唯一真正重要的是可强制执行的合同。也就是说,如果您的服务订阅了特定类型的合同,并且您有一个组件希望注入能够履行该合同的服务,那么您的DI层应该如实地注册一个可以履行该合同的服务。
在那时,您将获得有关bean优先级,限定符和应用程序配置文件的有趣有趣的内容,但这是一般的想法。
举一个具体的例子:javax.sql.DataSource
是一个由许多JDBC支持的解决方案(例如MySQL,Postgres,Oracle等)实现的接口。如果您希望有两个与两个不同数据库通信的bean,但又希望能够互换使用,则可以定义DataSource
类型的bean以使用和配置哪个数据源被创建。同样,这确实涉及诸如@Qualifier
之类的事情,以确保您在最合适的时间连接最具体的bean。
此外,最后一点对于回答问题的这一部分非常重要:
...,在这种情况下,两个线程可以并行更改bean中的数据吗?
创建具有自身固有状态的可注入bean是 非常 的明智做法。也就是说,如果您将SampleService
自身附加到某种内部具有集合的缓存状态,则基本上是在违反期望,因为您不知道该集合何时或多长时间添加一次元素或从中删除。
更好的约定是让bean可以引用有状态服务,但不要将状态存储在bean本身中(例如数据库连接,而不是整个数据库表)。