I'm learning spring and in my first application I have different kind to bean (#Repository,#Service). Now I read that the default scope for these bean is singleton.
My situation is the following, I have two services where I'm injecting the same Dao.
#Service
public class MyFirtsServiceImpl implements MyFirtsService{
#Autowired
UserDao userDao
}
#Service
public class MySecondServiceImpl implements MySecondService{
#Autowired
UserDao userDao
}
#Repository
public class UserDao {
//methods to manage the persistence
}
Now I have some doubts about this situation. Being userDao a singleton bean then the instance to UserDao injected in both services is the same? How the container manage this?
first of all the meaning of singleton design pattern is only one instance per appliction and spring container manage singleton design pattern.
When a bean is a singleton, only one shared instance of the bean will be managed, and all requests for beans with an id or ids matching that bean definition will result in that one specific bean instance being returned by the Spring container.
To put it another way, when you define a bean definition and it is scoped as a singleton, then the Spring IoC container will create exactly one instance of the object defined by that bean definition. This single instance will be stored in a cache of such singleton beans,
and all subsequent requests and references for that named bean will result in the cached object being returned.
for more help go here
Isn't singleton scope the easiest case for the controller to manage?
It creates a bean for your:
#Repository
public class UserDao {
Also #Autowire is by type. So when it sees this:
#Autowired
UserDao userDao
it finds that there is only one bean it has created(or will create) of type UserDao, and there is no ambiguity in which one to inject. So it injects that bean here.
When it encounters the second identical #Autowire situation, it repeats the decision and so injects the same bean. It is not even an interesting decision.
Related
It is a best practice to use constructor injection. However I can't acheive this with #PersistenceContext.
I would like to have the following constructor:
private final EntityManager entityManager;
#Autowired
public MyService(#PersistenceContext EntityManager entityManager) {
this.entityManager = entityManager;
}
But I can't since #PersistenceContext is only applicable to TYPE, METHOD and FIELD.
Q: How do I inject a container-managed EntityManager through constructor injection?
You seem to be using spring so your solution will be rather easy :
#Component
#Scope("prototype")
public class MyPersistenceContainer
{
#PersistenceContext
private EntityManager em;
public EntityManager getEntityManager()
{
return em;
}
}
And now you can simply inject an instance of this class in your constructor, it will always hold a valid EntityManager (because of the bean scope). Mind you : in a web environment you probably should use #SessionScope or even #RequestScope instead of prototype, this will save resources
But there is something to consider :
When using singleton-scoped beans that have dependencies on beans that
are scoped as prototypes, please be aware that dependencies are
resolved at instantiation time. This means that if you dependency
inject a prototype-scoped bean into a singleton-scoped bean, a brand
new prototype bean will be instantiated and then dependency injected
into the singleton bean... but that is all. That exact same prototype
instance will be the sole instance that is ever supplied to the
singleton-scoped bean, which is fine if that is what you want.
However, sometimes what you actually want is for the singleton-scoped
bean to be able to acquire a brand new instance of the
prototype-scoped bean again and again and again at runtime. In that
case it is no use just dependency injecting a prototype-scoped bean
into your singleton bean, because as explained above, that only
happens once when the Spring container is instantiating the singleton
bean and resolving and injecting its dependencies. If you are in the
scenario where you need to get a brand new instance of a (prototype)
bean again and again and again at runtime, you are referred to the
section entitled Section 4.3.7, “Method Injection”
So if you want to inject your "entity manager container-bean" into singleton beans (which is the default scope), have a look at https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-method-injection
Its rather important to set your scopes correctly, otherwise you might have (and will have) database inconsistencies, deadlocks or worse
It sould be possible using Spring Data. But if you would not like to use Spring Data in your project for some reason (e.g. you're just making a legacy project a bit better), you can create the following FactoryBean to make EntityManager injectable via constructor injection:
/**
* Makes the {#link EntityManager} injectable via <i>#Autowired</i>,
* so it can be injected with constructor injection too.
* (<i>#PersistenceContext</i> cannot be used for constructor injection.)
*/
public static class EntityManagerInjectionFactory extends AbstractFactoryBean<EntityManager> {
#PersistenceContext
private EntityManager entityManager;
#Override
public Class<?> getObjectType() {
return EntityManager.class;
}
#Override
protected EntityManager createInstance() {
return entityManager;
}
}
Please note, that because we use the #PersistenceContext annotation internally, the returned EntityManager will be a proper thread-safe proxy, as it would have been injected directly at the place of usage with field injection.
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");
}
}
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.
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.
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.
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).
I am having some problems understanding Java CDI.
I have a stateful bean which receives per injection a some objects:
#Stateful
public class MyBean {
#Inject
private MyDAO myDAO;
}
and this is the DAO:
public class MyDAO{
}
I thought it would not work, because I have not defined the bean as #Stateless, #Stateful, etc.
But it works.
The question is: what scope will this bean have? Will it be a stateful bean?
In this context MyDAO has a Dependent pseudo-scope which means that it will follow the lifecycle of the bean into which it is injected (in your case EJB stateful MyBean bean). Everything explained here.
I'm working with some existing code and it is doing things I haven't seen before. I've dealt with autowiring prototype beans into singletons using method injection or getting the bean from the context using getBean(). What I am seeing in this code I am working on is a bean that is a prototype and retrieved using getBean(), and it has autowired dependencies. Most of these are singleton beans, which makes sense. But there is an autowire of another prototype bean, and from what I see, it does seem like it is getting a new bean. My question is when you autowire a prototype into a prototype, will that give you a new instance? Since the autowire request is not at startup but rather when this bean is created, does it go and create a new instance? This goes against what I thought about autowire and prototype beans and I wanted to hear an answer from out in the wild. Thanks for any insight. I'm trying to minimize my refactoring of this code as it is a bit spaghetti-ish.
example:
#Scope("prototype")
public class MyPrototypeClass {
#Autowired
private ReallyGoodSingletonService svc;
#Autowired
private APrototypeBean bean;
public void doSomething() {
bean.doAThing();
}
}
#Scope("prototype)
public class APrototypeBean {
private int stuffgoeshere;
public void doAThing() {
}
}
So when doSomething() in MyPrototypeClass is called, is that "bean" a singleton or a new one for each instance of MyPrototypeClass?
In your example, the APrototypeBean bean will be set to a brand new bean which will live through until the instance of MyPrototypeClass that you created is destroyed.
If you create a second instance of MyPrototypeClass then that second instance will receive its own APrototypeBean. With your current configuration, every time you call doSomething(), the method will be invoked on an instance of APrototypeBean that is unique for that MyPrototypeClass object.
Your understanding of #Autowired or autowiring in general is flawed. Autowiring occurs when an instance of the bean is created and not at startup.
If you would have a singleton bean that is lazy and that bean isn't directly used nothing would happen as soon as you would retrieve the bean using for instance getBean on the application context an instance would be created, dependencies get wired, BeanPostProcessors get applied etc.
This is the same for each and every type of bean it will be processed as soon as it is created not before that.
Now to answer your question a prototype bean is a prototype bean so yes you will receive fresh instances with each call to getBean.
Adding more explanation to #Mark Laren's answer.
As explained in Spring 4.1.6 docs
In most application scenarios, most beans in the container are
singletons. When a singleton bean needs to collaborate with another
singleton bean, or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by
defining one bean as a property of the other. A problem arises when
the bean lifecycles are different. Suppose singleton bean A needs to
use non-singleton (prototype) bean B, perhaps on each method
invocation on A. The container only creates the singleton bean A once,
and thus only gets one opportunity to set the properties. The
container cannot provide bean A with a new instance of bean B every
time one is needed.
Below approach will solve this problem, but this is not desirable because this code couples business code with Spring framework and violating IOC pattern. The following is an example of this approach:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
So, there are 2 desirable ways to solve this problem.
1. Using Spring's method injection
As name suggests, Spring will implement & inject our abstract method by using #Lookup annotation from Spring 4 or tag if you use xml version. Refer this DZone article.
By using #Lookup.
from Java Doc...
An annotation that indicates 'lookup' methods, to be overridden by the
container to redirect them back to the BeanFactory for a getBean call.
This is essentially an annotation-based version of the XML
lookup-method attribute, resulting in the same runtime arrangement.
Since:
4.1
#Component
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
#Lookup
public MyClass2 myClass2(){
return null; // No need to declare this method as "abstract" method as
//we were doing with earlier versions of Spring & <lookup-method> xml version.
//Spring will treat this method as abstract method and spring itself will provide implementation for this method dynamically.
}
}
The above example will create new myClass2 instance each time.
2. Using Provider from Java EE (Dependency Injection for Java (JSR 330)).
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public static class SomeRequest {}
#Service
public static class SomeService {
#Autowired
javax.inject.Provider<SomeRequest> someRequestProvider;
SomeRequest doSomething() {
return someRequestProvider.get();
}
}
The above example will create new SomeRequest instance each time.
I have this requirement: I have a singleton bean and I have a method annotated with #PostConstruct where I perform some initialization. One of the initialization is to read some values from a DB, so I want to inject in this method a Stateless bean which is a service bean that access the DB. I don't want to inject the stateless bean as a field in the singleton bean because it is needed only in this method (nowhere else in the singleton bean). To do so I did wrote this in singleton bean:
#Singleton
public class MySingletonBean {
#PostConstruct
#EJB
public void init(SLSBService service) { /* use service to read from DB */ };
...
}
The problem is that the Singleton bean can not be instantiated. Any idea? Thank you in advance.
As the #PostConstruct annotated (callback) method is actually called after all references are resolved (all beans injected) I do not think this construct works.
What you could do or try out is to remove the #PostConstruct and using normal setter injection. However, be aware that other injected resources have not necessarily been resolved at this time.
#EJB
public void setService(SLSBService service){
service.doSmg();
}
#Stateless
public class SLSBService{
#PersistenceContext
private EntityManager em;
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public void doSmg() {
Member member = new Member();
member.setEmail("bla#bla.de");
member.setName("fubu");
member.setPhoneNumber("453454534535");
em.persist(member);
}
}
/* edit */
Just had some time for trying it out. The construct should be usable for DAOs, as the method is executed within a transaction and also the EntityManager (within the SLBService) is injected properly. And as expected references to other EJBs have not be resolved yet, so be aware of that.