I once read that for setter injection, the dependencies are not injected until they are needed. However, when I run a little test on that, I see that in using setter injection, dependencies are injected at application startup time. Actually, when is setter injection being called in the Spring bean life cycle ? and what does it mean by "dependencies are not injected until they are needed" ?
#Service
public class MainService {
private DependencyService dependencyService;
#Autowired
public void setDependencyService(DependencyService dependencyService) {
this.dependencyService = dependencyService;
}
#PostConstruct
public void afterConstruct() {
System.out.println("Created MainService bean");
if (service != null) {
System.out.println("DependencyService is injected");
}
}
}
#Service
public class DependencyService {
#PostConstruct
public void afterConstruct() {
System.out.println("created DependencyService bean");
}
}
On application startup, the console result:
Created DependencyService bean
Created MainService bean
DependencyService is injected
Dependencies are always injected right after or during the bean is instantiated no matter you use field injection , setter injection or constructor injection .
So it depends on when the bean is initialised. By default all beans will be initialised eagerly at startup which means that their dependencies are also injected at startup
It is generally a desirable behaviour as it allows you to discover error due to bean configuration at startup rather than several hours or even days later.
You can change a bean to be lazy initialised until they are needed by annotating it as #Lazy. So if you want MainService to be lazy initialised until it is accessed (i.e. its setter injection does not happen at start up) , you have to :
#Service
#Lazy
public class MainService {
}
Related
what is the main difference between injecting objects with #Autowired and injecting without it ?
I know that spring will initialize the bean , but what it is really offering ?
There are several ways to configure Spring beans and inject dependencies using Spring. One way is by using constructor injection, where the constructor of your Spring bean has arguments which are the dependencies that should be injected:
#Component
public class MyBean {
private final SomeDependency something;
#Autowired
public MyBean(SomeDependency something) {
this.something = something;
}
}
However, since Spring 4.3, it is not necessary anymore to use #Autowired on such a constructor (click link for Spring documentation). So you can write it without the #Autowired:
#Component
public class MyBean {
private final SomeDependency something;
public MyBean(SomeDependency something) {
this.something = something;
}
}
This will work exactly the same as the code above - Spring will automatically understand that you want the dependency to be injected via the constructor. The fact that you can leave out #Autowired is just for convenience.
So, to answer your question: there is no difference.
#Autowired (so the injection) in some situation cannot be used, an example is if your autowired bean not ready because of some async stuff but in the target bean you want to use that.
So in this situation do not use inject (#Autowired) it is better to inject the ApplicationContext and in the exact moment get your bean from there by name or by class (there is a lot off possibilities there).
You can consider the #Autowired with the #Lazy annotation too.
I have the following scenario where I am running into null pointer exception because bean not getting initialized and leading to failure in my server failing to boot.
There is a newly introduced call in PostConstruct annotated method which is failing. The same call is being made in another method which is not in PostConstruct which executes correctly and not cause any issue.
#Component
#Lazy
#Primary
class Parent{
#Autowired
private DesignContextService designContextService;
#PostConstruct
private void init(){
designContextService.getMethod();// fails
}
private void someFunction(){
designContextService.getMethod();// executes successfully
}
}
}
Class DesignContextService{
#Autowired
private ContextService contextService;
public void getMethod(){
contextService.isContextCreated();
...
}
// Below classes present in another jar
class ContextService{
#Inject
public ContextAdapter contextAdapter;
public void isContextCreated(){
contextAdapter.isEstablished();// contextAdapter is null . Throws exception here
}
}
}
Error Stack trace :
at
Caused by org.springframework.beans.factory.BeanCreationException : Error creating bean ...
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:137)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620)
This is because of the #lazy annotation. As specified in the documentation:
The default behavior for ApplicationContext implementations is to eagerly pre-instantiate all singleton beans at startup. Pre-instantiation means that an ApplicationContext will eagerly create and configure all of its singleton beans as part of its initialization process. Generally this is a good thing, because it means that any errors in the configuration or in the surrounding environment will be discovered immediately (as opposed to possibly hours or even days down the line).
Please look into the following link for reference: Using Spring #Lazy and #PostConstruct annotations
Spring: how to initialize related lazy beans after main bean creation
Old code:
#Component("someFactory")
public class SomeFactoryImpl implements SomeFactory{
#Autowired
private List<SomeTransformer<?, ?>> someTransformers;
New code:
#Component("someFactory")
public class SomeFactoryImpl implements SomeFactory {
private List<SomeTransformer<?, ?>> someTransformers;
#Autowired
public SomeFactoryImpl(List<SomeTransformer<?, ?>> someTransformers) {
this.someTransformers = someTransformers;
}
Here I got:
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'someFactory': Requested bean is
currently in creation: Is there an unresolvable circular reference?
Does Spring have some problems when autowiring through constructor?
Check the Spring documentation (Look for 'Circular dependencies').
Unlike the typical case (with no circular dependencies), a circular
dependency between bean A and bean B forces one of the beans to be
injected into the other prior to being fully initialized itself (a
classic chicken/egg scenario).
The difference lies in the following;
In Setter injection, the bean references will only be constructed once they are required. You can probably recreate the same problem with setter injection when annotating the setter with #Required as this will cause the bean to be created immediately.
In Constructor injection, Spring cannot decide which of the beans should be created first because they depend on one another. The problem is exposed immediately. A possible workaround is using constructor injection annotated with #Lazy;
#Component
public class CircularClassA {
private CircularClassB classB;
#Autowired
public CircularDependencyB(#Lazy CircularClassB classB) {
this.classB = classB;
}
}
This will create only a proxy of classB instead of fully initializing it. It gets fully initialized when needed, just as with setter injection.
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.