Some doubts about lazily instantiation in Spring? How it works? - java

I am studying for the Spring Core certification and I have some doubts related this questions:
In Spring are beans lazily or eagerly instantiated by default? How do
you alter this behavior?
So I know that the bean are eagerly instantiated by default by the Spring Container and I know that it automatically create my beans (declared into the configuration) in right order with its dependencies injected. And I know that after dependency injection each bean goes through a post-processing phase in which Further configuration and initialization may occur. So at the ending of this phase my beans are fully initialized and ready for use.
So I think that the meaning of eagerly beans instantiation is the behavior of the creation of the declared bean before the application start. Is it right or am I missing something?
At the contrary the lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed.
And so I have my first doubt about it. Is this the same behavior of a classi Java application (that don't use Spring) in which, at a certain point of the program execution, I declare a statment like this:
private void myMethod() {
....................................
....................................
....................................
DO SOMETHING
...................................
MyObject myObject = new MyObject(); // Is it lazily instantiated?
....................................
....................................
}
So in the case of the previous snippet is it the MyObject myObject lazily instantiated (this is not instantiated before that my application start but it is instantiated at certain pint of the application execution) or am I missing something?
By the way coming back at the original question: How can I alter the default behavior and how can I instantiate a bean in a lazily way?
Reading on the course documentation I found that Spring support Lazy beans ant it say this assertion:
Lazy beans are supported – only created when getBean() called. Not
recommended, often misused: #Lazy or <bean lazy-init=“true” ...>
So I thing to understand that (by I am not sure about it) that if into my Java code I do something like:
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) appContext.getBean("hello");
the bean having id hello is lazily instantiated. Is it true or is it wrong or missing something?
If it is true from what I can understand reading the previous documentation it is not a good idea use the previous solution (why?) but it is better to choose annotate the bean configuration (into the Java configuration class) that have to be lazily instantiated with the #Lazy annotation or use <bean lazy-init=“true” ...> into the XML configuration (of the bean).
So it means that #Lazy in Spring can be used inside #Configuration classes. The bean which has been declared with #Lazy annotation will not be initialized by spring container. #Lazy will be initialized by container only when that bean will be accessed somewhere in code.
Ok, but now my doubt is: how can I access to a bean that is not yet instantiated? Can you show me an example of it?

Related

Beans created by ImportBeanDefinitionRegistrar during autoconfiguration are not eligible for all bean postprocessors

I have implemented ImportBeanDefinitionRegistrar to create bean definitions from external source. It has to be registrar since I do not know in advance how many bean definitions will be created.
When I use the registrar on my Application class like this:
#SpringBootApplication
#Import(GenesysRegistrar.class)
public class IntegrationServer {
...
}
everything works fine.
I wanted to make the import automatic for every application that uses the JAR that contains the registrar so I have created following class:
#Configuration
#Import(GenesysRegistrar.class)
public class GenesysAutoConfiguration {
/**/
}
and registered it in META-INF/spring.factories under key org.springframework.boot.autoconfigure.EnableAutoConfiguration.
Now auto-configuration works, but I get following messages in log:
Bean 'xxx' of type [XXX] is not eligible for getting processed by all BeanPostProcessors
What is the difference between importing the registry from aplication class and from autoconfiguration class? I have found that following post processors are created AFTER my beans:
methodValidationPostProcessor
persistenceExceptionTranslationPostProcessor
webServerFactoryCustomizerBeanPostProcessor
errorPageRegistrarBeanPostProcessor
I have tried to put #AutoConfigureOrder(Integer.MAX_VALUE) on my auto-configuration class, but it does not change anything.
Any ideas how can I fix the order so beans from definitions created by my registrar are processed after all post processors? Why Spring creates them before all post processors? Any why the issue does not happen when using #Import on application class?
Early initialized beans are dependencies injected to other bean factoy by constructor injection.
If the bean factory uses property injection instead of construcotr injection it does not happen.
Question is if constructor injection on factory bean is "bad practise" - have not found anything that prohibits it.
Created ticket to spring-boot (as it happens only during boot auto-configuraiton):
Issue #20219

get a bean instance inside a non managed spring class if I am retrieving it through ApplicationContext getBean method

I know I can not use #Autowired annotation in a non managed spring class. But I notice I do able to get a bean instance inside a non managed spring class if I am retrieving it through ApplicationContext getBean method.
can someone explain me why is that ? what is the different between the options ? in both spring doesn't know the non managed class
1) You can use #Autowired in a non-managed spring class if you use #Configurable -with the usage of internal aspect weaving spring will manage to autowired the referenced beans into your "Configurable" class when it is constructed with the "new" operator. Here is an article how this works: http://www.javacodegeeks.com/2013/09/spring-configurable-magic.html
If a class is not configurable spring cannot notice when a new instance is created to autowire its references.
2) The ApplicationContext is "Central interface to provide configuration for an application." Here you have access to the whole spring managed beans etc. That's why you can get everything due to accessing it via ApplicationContext. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html
ok, so here's the major points:
the "bean declaration" (either in xml or java) is just a recipe of how to instantiate the object (not a object itself).
when spring application boots, the beanFactory receives this recipes from beanDefinitionReader, instantiates objects according to them (recipes) and then pass them (objects) to a list of beanPostProcessors (several times) that are "injecting" dependences to the instantiated objects and then puts the objects into hashMap.
roughly saying applicationContext is a class exposing access to this beans;
and that's how you can access this beans out of spring application using applicationContext.
another thing is that, actually you can inject beans into non managed beans through #Configurable. in this case the AspectJ would be used for making this work

Spring creating multiple instances of a singleton?

I have a graph of Spring beans which autowire each other. Heavily simplified illustration:
<context:annotation-config/>
<bean class="Foo"/>
<bean class="Bar"/>
<bean class="Baz"/>
...
public class Foo {
#Autowired Bar bar;
#Autowired Baz baz;
}
public class Bar {
#Autowired Foo foo;
}
public class Baz {
#Autowired Foo foo;
}
All of these beans don't have scope specified which imply they are singletons (making them explicit singletons doesn't change anything, I've tried).
The problem is that after the instantiation of a single application context, instances of Bar and Baz contain different instances of Foo. How could this happen?
I have tried to create public no args constructor for Foo and debugging has confirmed Foo is created more than once. The stack trace for all of these creations is here.
I have also tried to enable debug logging for Spring, and among all other lines, got the following:
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
I understand that my beans are cross-referencing each other, but I would expect Spring framework to respect singleton scope and initialize a singleton bean once, and then autowire it to whoever wants it.
The interesting fact that if I use old school private constructor with public static Foo getInstance accessor, this works just fine - no exceptions are thrown during the context setup.
FWIW, I am using Spring version 3.0.5 (also tried with 3.1.2, same results) with o.s.c.s.ClassPathXmlApplicationContext(String ...configLocations) constructor.
I can easily convert my code to use static initializer but I want to understand why would Spring behave this way. Is this a bug?
EDIT: Some additional investigation showed that
After the application context is initialized, all subsequent requests to context.getBean(Foo.class) always return the same instance of Foo.
Replacing #Autowired with setters (about 20 usages of this bean) still results multiple constructions of this object, but all dependencies are injected with the same reference.
To me above suggests that this is a Spring bug pertaining to #Autowired implementation. I am going to post to Spring community forums and post back here if I manage to obtain anything useful.
Child context(s) can reinstantiate the same singleton beans if you are not careful with context:component-scan annotations (there are other Spring context scan annotations as well such as MVC ones and others). This is a common problem when using Spring servlets in web applications, see Why DispatcherServlet creates another application context?
Make sure you are not re-scanning your components in child contexts, or you are scanning only specific packages/annotations and excluding said packages/annotations from root context component scan.
For some reason we are getting this popping up randomly in integration tests and services as well (spring version 4.1.4, java 1.8).
Looks like there might be more than one culprit - Autowiring appeared to be causing this at first.
However, we have resolved the most consistent failures by ensuring we give each impacted bean an 'id' field.
Try using setter injection instead of constructor way and see if it works.In the spring bean xml specify Bean A ref to Bean B and vice versa.
My Spring configuration was like follows:
<context:annotation-config/>
<bean class="Bar" />
<bean class="Foo" />
<bean class="Baz" />
Classes are identical to yours
Test app like follows:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
/**
* #param args
*/
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/spring/testctx.xml");
Foo foo = ctx.getBean(Foo.class);
Baz baz = ctx.getBean(Baz.class);
Bar bar = ctx.getBean(Bar.class);
System.out.println(foo.equals(baz.foo));
System.out.println(foo.equals(bar.foo));
System.out.println(baz.equals(foo.baz));
System.out.println(foo.baz.toString());
System.out.println(baz.toString());
System.out.println(foo.bar.toString());
System.out.println(bar.toString());
}
}
Output from test app like follows:
true
true
true
Baz#8aef2b
Baz#8aef2b
Bar#215bf054
Bar#215bf054
Using 3.0.6 it works perfectly fine (singleton beans are indeed singletons). There might be something else you did not illustrate here messing up your configuration. Of course, as a side note, using default package may cause some misterious magic to happen ;-)

Spring circular reference example

I have a circular reference in one of my projects at work using spring, which I am unable to fix, and fails with the following error at startup:
'org.springframework.security.authenticationManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
I tried to recreate the same problem at a smaller level in a sample project (without all the details of my work project). I have however been unable to come up with a plausible scenario where spring fails with an error.
Here's what I have:
public class ClassA {
#Autowired
ClassB classB;
}
public class ClassB {
#Autowired
ClassC classC;
}
#Component
public class ClassC {
#Autowired
ClassA classA;
}
#Configuration
public class Config {
#Bean
public ClassA classA() {
return new ClassA();
}
#Bean
public ClassB classB() {
return new ClassB();
}
}
I have a similar scenario in my project, which fails, and I was expecting spring to complain in my sample project as well. But it works fine! Can someone give me a simple example of how to break spring with the circular reference error?
Edit: I fixed the issue using javax.inject.Provider. The only other difference in the 2 projects was the annotations used were javax.inject.Inject and javax.annotation.ManagedBean in place of #Autowired and #Component.
You could use #Lazy to indicate that the bean is lazily created, breaking the eager cycle of autowiring.
The idea is that some bean on the cycle could be instantiated as a proxy, and just at the moment it is really needed it will be initialized. This means, all beans are initialized except the one that is a proxy. Using it for the first time will trigger the configuration and as the other beans are already configured it will not be a problem.
From one Issue in Spring-Jira:
#Lazy annotation that can be used in conjunction with #Configuration
to indicate that all beans within that configuration class should be
lazily initialized. Of course, #Lazy may also be used in conjunction
with individual #Bean methods to indicate lazy initialization on a
one-by-one basis.
https://jira.springsource.org/browse/SJC-263
Meaning that annotating your bean as #Lazy would be enough. Or if you prefer just annotate the configuration class as #Lazy as follows:
#Configuration
#Lazy
public class Config {
#Bean
public ClassA classA() {
return new ClassA();
}
#Bean
public ClassB classB() {
return new ClassB();
}
}
If you implement an interface of your beans this will work quite well.
This is an old thread, so I guess you almost forgot about the issue, but I want to let you know about the mystery. I encountered the same problem, and mine didn't go away magically, so I had to resolve the problem. I'll solve your questions step by step.
1. Why you couldn't reproduce the circular reference exception?
Because Spring takes care of it. It creates beans and injects them as required.
2. Then why does your project produce the exception?
As #sperumal said, Spring may produce circular exception if you use constructor injection
According to the log, you use Spring Security in your project
In the Spring Security config, they do use constructor injection
Your beans which injects the authenticationManager had the circular reference
3. Then why has the exception gone away mystically?
The exception may or may not occur depends on the creation order of beans. I guess you made several *context.xml files or so, and load them with config something like below in web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:*-context.xml</param-value>
</context-param>
The xml files will be loaded by XmlWebApplicationContext class and the loading order of files are not guaranteed. It just loads files from the file system. The problem is here. There's no problem if the class loads the application context file first, because your beans are already created when they are used for the construction injection of Spring Security. But, if it loads the Spring Security context file first, the circular reference problem occurs, because Spring tries to use your beans in the constructor injection before they had been created.
4. How to solve the problem?
Force the loading order of the xml files. In my case, I loaded the security context xml file at the end of the application context file by using <import resource="">. The loading order can be changed depends on environments even with the same code, so I recommend setting the order to remove potential problems.
According to Spring documentation, it is possible to get Circular dependency issue or BeanCurrentlyInCreationException by using constructor injection.
The solution to fix the issue is to use setters instead of Constructor injection.
Reference http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html.

when is a spring bean instantiated

ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol.xml");
Performer performer = (Performer) ctx.getBean("duke");
performer.perform();
In the above, when are the beans instantiated, when the ApplicationContext is created or when the getBean() is called?
Assuming the bean is a singleton, and isn't configured for lazy initialisation, then it's created when the context is started up. getBean() just fishes it out.
Lazy-init beans will only be initialised when first referenced, but this is not the default. Scoped beans (e.g. prototype-scoped) will also only be created when first referenced.
According to Spring documentation,
The default behavior for ApplicationContext implementations is to eagerly pre-instantiate all singleton beans at startup.
Also, you can set them to load lazily.
For reference, see
Lazy-initialized beans and
Bean scopes
Here's a brief description of when beans are created:
A singleton bean (which is the default scope) that does not have the lazy-init property set to true (default is false) is constructed when the application context is created
A singleton bean that does have the lazy-init property set to true is constructed when it is first requested
A bean set in any other scope is created when it is first requested (for that scope).
By default, all beans are singletons, so whenever Application context gets created, they are all pre-loaded. If, specifically, any singleton bean has an attribute lazy-init="true" set, it will be lazy-loaded, i.e. it will be instantiated when the getBean method is called for the first time.
For other scopes, beans will be instantiated whenever they are requested.
It depends what is the scope of the bean you are calling with getBean() method.
If it is 'Singleton', it is pre-instantiated by the ApplicationContext.
If you are using BeanFactory as an IOC Container, then it uses lazy initialization and the beans will be instantiated only when you call the getBean() method.
This is an advantage of ApplicationContext over BeanFactory that it solves Circular Dependency problem.
By default, Spring ApplicationContext eagerly creates and initializes all ‘singleton scoped‘ beans during application startup itself. ApplicationContext makes the bean available in BeanFactory. getBean() returns the instance of the bean.
By default it's created when the context is started up but the order depends on dependencies.
If we have the following classes :
#Component
public class A{
}
#Component
public class B{
#Autowired
A a;
}
Class A will be created before class B because class B depends on class A.
Basically, when you run ApplicationContext, it automatically creates all the Annotated beans and makes ready them to use for you.
If you don't need some of them, you can annotate them with #Lazy and they will not instantiated when you run the application

Categories