Reputation: 40048
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? how one bean can be @Autowired
in two different classes?
How SampleService
bean can be @Autowired
in SampleController2
and SampleController3
at a time ?
And is this recommended approach? and in this case two threads can parallely change the data inside 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");
}
}
Upvotes: 2
Views: 14218
Reputation: 106430
The intention behind dependency injection and inversion of control is simple:
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.
You get into fun and exciting stuff with bean priority, qualifiers and application profiles at that point, but this is the general idea.
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. 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. Again, this does involve things like @Qualifier
to ensure you wire in the most specific bean at the most appropriate time.
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?
It is very unwise to create an injectable bean with its own inherent state. 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.
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).
Upvotes: 0
Reputation: 159096
Here is a simplified view of what Spring does on startup:
// 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
.
The beans are added to a repository, so you can look them up by name or type at any later point in time.
Upvotes: 4
Reputation: 2668
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.
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. You would most of the time want to keep your beans stateless for that reason.
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
. See Spring bean scopes docs.
Upvotes: 4