简体   繁体   English

Singleton bean如何在不同的地方自动布线

[英]How Singleton bean can be Autowired in different places spring boot

I'm confused at this point, and i know all spring boot applications beans are singleton, according to my understanding if we have class annotated with @Service annotation that bean can be @Autowired in only one class (correct me if i'm wrong) here is the code that works fine, but i'm trying to understand how it works? 在这一点上,我很困惑,根据我的理解,如果我们使用@Service批注对类进行注释,那么bean只能在一个类中进行@Autowired (如果我错了,请纠正我) )这是可以正常工作的代码,但我试图了解它的工作原理? how one bean can be @Autowired in two different classes? 如何在两个不同的类中@Autowired一个bean?

How SampleService bean can be @Autowired in SampleController2 and SampleController3 at a time ? 如何在SampleController2SampleController3中一次@Autowired SampleService bean?

And is this recommended approach? 这是推荐的方法吗? and in this case two threads can parallely change the data inside bean? 在这种情况下,两个线程可以并行更改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");
    }
 }

By default, as you mentioned, all Spring beans are singletons, but your second assumption is wrong: the same bean can be autowired in many other beans. 正如您提到的,默认情况下,所有Spring Bean都是单例的,但是您的第二个假设是错误的:同一bean可以在许多其他bean中自动装配。

In fact that's the whole point of them being singletons. 实际上,这就是单身人士的全部要点。

That also means two different threads could change the state of the same bean indeed. 这也意味着两个不同的线程确实可以更改同一bean的状态。 You would most of the time want to keep your beans stateless for that reason. 出于这种原因,您大多数时候都希望使bean保持无状态。

If you really ever need to have one different instance of a bean for each place where it is autowired, you can change the scope of that bean to prototype . 如果确实需要在每个自动装配的位置使用一个bean的不同实例,则可以将该bean的范围更改为prototype See Spring bean scopes docs . 参见Spring bean scopes文档

Here is a simplified view of what Spring does on startup: 这是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

As you can see, the singleton bean sampleService2 is autowired into both sampleController2 and sampleController3 . 如您所见,单例bean sampleService2被自动连接到sampleController2sampleController3

The beans are added to a repository, so you can look them up by name or type at any later point in time. Bean被添加到存储库中,因此您可以在以后的任何时间按名称或类型进行查找。

The intention behind dependency injection and inversion of control is simple: 依赖项注入和控制反转的意图很简单:

  • You define your injectables (like services) once , and they are instantiated once (unless you specify otherwise). 定义你的注射剂(如服务) 一次 ,以及(除非另行指定),他们被实例化一次
  • Those injectables are then used everywhere applicable , and you don't control their lifecycle, scope or state. 然后,这些可注射剂将在所有适用的地方使用 ,并且您无法控制其生命周期,作用域或状态。

While I feel like the last point answers your primary question fairly tacitly, I'll elaborate - in a DI context, the only thing that really matters are enforceable contracts. 尽管我觉得最后一点很默契地回答了您的主要问题,但我会详细说明-在直接投资的背景下,唯一真正重要的是可强制执行的合同。 That is to say, if your service subscribes to a specific type of contract, and you have a component which wishes to inject a service which fulfills that contract, then your DI layer should faithfully register a service which can fulfill that contract. 就是说,如果您的服务订阅了特定类型的合同,并且您有一个组件希望注入能够履行该合同的服务,那么您的DI层应该如实地注册一个可以履行该合同的服务。

You get into fun and exciting stuff with bean priority, qualifiers and application profiles at that point, but this is the general idea. 此时,您将获得有关bean优先级,限定符和应用程序配置文件的有趣知识,但这是总的想法。

For a concrete example: javax.sql.DataSource is an interface which is implemented by many JDBC-backed solutions, such as MySQL, Postgres, Oracle, and others. 举一个具体的例子: javax.sql.DataSource是一个由许多JDBC支持的解决方案(例如MySQL,Postgres,Oracle等)实现的接口。 If you wish to have two different beans which talk to two different databases, but you want to be able to use those interchangeably, then you define a bean of type DataSource to use and configure which data source gets created. 如果你想有两个不同的豆子这跟两个不同的数据库,但要能够交替使用的,那么你定义类型的bean的DataSource使用和配置数据源被创建。 Again, this does involve things like @Qualifier to ensure you wire in the most specific bean at the most appropriate time. 同样,这确实涉及到@Qualifier事情,以确保您在最合适的时间连接最具体的bean。

Also, that last point is fairly important to answer this part of your question: 此外,最后一点对于回答问题的这一部分非常重要:

... and in this case two threads can parallely change the data inside bean? ...并且在这种情况下,两个线程可以并行更改Bean中的数据?

It is very unwise to create an injectable bean with its own inherent state. 创建具有其固有状态的可注入bean是非常不明智的。 That is, if you have SampleService attach itself to some sort of cached state with a collection inside of it, you're basically violating expectations since you don't know when or how often that collection is going to have elements added to it or removed from it. 也就是说,如果您让SampleService将其自身附加到某种内部带有集合的缓存状态,则基本上是在违反期望,因为您不知道该集合何时或多SampleService添加或删除元素从中。

The better convention is to have beans which can reference stateful services, but don't store that state in the bean itself (such as a database connection, but not entire database tables). 更好的约定是让bean可以引用有状态服务,但不要将该状态存储在bean本身中(例如数据库连接,而不是整个数据库表)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM