when is a spring bean instantiated - java

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

Related

Do Spring prototype beans need to be destroyed manually?

I noticed that the #PreDestroy hooks of my prototype scoped Spring beans were not getting executed.
I have since read here that this is actually by design. The Spring container will destroy singleton beans but will not destroy prototype beans. It is unclear to me why. If the Spring container will create my prototype bean and execute its #PostConstruct hook, why will it not destroy my bean as well, when the container is closed? Once my Spring container has been closed, does it even make sense to continue using any of its beans? I cannot see a scenario where you would want to close a container before you have finished with its beans. Is it even possible to continue using a prototype Spring bean after its container has been closed?
The above describes the puzzling background to my primary question which is: If the Spring container is not destroying prototype beans, does that mean a memory leak could occur? Or will the prototype bean get garbage-collected at some point?
The Spring documentations states:
The client code must clean up prototype-scoped objects and release
expensive resources that the prototype bean(s) are holding. To get the
Spring container to release resources held by prototype-scoped beans,
try using a custom bean post-processor, which holds a reference to
beans that need to be cleaned up.
What does that mean? The text suggests to me that I, as the programmer am responsible for explicitly (manually) destroying my prototype beans. Is this correct? If so, how do I do that?
For the benefit of others, I will present below what I have gathered from my investigations:
As long as the prototype bean does not itself hold a reference to another resource such as a database connection or a session object, it will get garbage collected as soon as all references to the object have been removed or the object goes out of scope. It is therefore usually not necessary to explicitly destroy a prototype bean.
However, in the case where a memory leak may occur as described above, prototype beans can be destroyed by creating a singleton bean post-processor whose destruction method explicitly calls the destruction hooks of your prototype beans. Because the post-processor is itself of singleton scope, its destruction hook will get invoked by Spring:
Create a bean post processor to handle the destruction of all your prototype beans. This is necessary because Spring does not destroy prototype beans and so any #PreDestroy hooks in your code will never get called by the container.
Implement the following interfaces:
1.BeanFactoryAware
This interface provides a callback method which receives a Beanfactory object. This BeanFactory object is used in the post-processor class to identify all prototype beans via its BeanFactory.isPrototype(String beanName) method.
2. DisposableBean
This interface provides a Destroy() callback method invoked by the Spring container. We will call the Destroy() methods of all our prototype beans from within this method.
3. BeanPostProcessor
Implementing this interface provides access to post-process callbacks from within which, we prepare an internal List<> of all prototype objects instantiated by the Spring container. We will later loop through this List<> to destroy each of our prototype beans.
3. Finally implement the DisposableBean interface in each of your prototype beans, providing the Destroy() method required by this contract.
To illustrate this logic, I provide some code below taken from this article:
/**
* Bean PostProcessor that handles destruction of prototype beans
*/
#Component
public class DestroyPrototypeBeansPostProcessor implements BeanPostProcessor, BeanFactoryAware, DisposableBean {
private BeanFactory beanFactory;
private final List<Object> prototypeBeans = new LinkedList<>();
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanFactory.isPrototype(beanName)) {
synchronized (prototypeBeans) {
prototypeBeans.add(bean);
}
}
return bean;
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
#Override
public void destroy() throws Exception {
synchronized (prototypeBeans) {
for (Object bean : prototypeBeans) {
if (bean instanceof DisposableBean) {
DisposableBean disposable = (DisposableBean)bean;
try {
disposable.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
}
prototypeBeans.clear();
}
}
}
Your answer is great. I'd also like to share some notes on an alternative solution that allows prototype members which are natively managed by the Spring IoC container lifecycle through the use of the inner beans.
I recently wrote an answer to a separate question on inner beans. Inner beans are created by assigning bean property values as BeanDefinition objects. Bean definition property values are automatically resolved to (inner) instances (as managed singleton beans) of the bean that they define.
The following XML context configuration element can be used to create distinct autowireable ForkJoinPool beans for each reference which will be managed (#PreDestroy will be called on context shutdown):
<!-- Prototype-scoped bean for creating distinct FJPs within the application -->
<bean id="forkJoinPool" class="org.springframework.beans.factory.support.GenericBeanDefinition" scope="prototype">
<property name="beanClass" value="org.springframework.scheduling.concurrent.ForkJoinPoolFactoryBean" />
</bean>
This behavior is contingent upon the reference being assigned as a property value of a bean definition, though. This means that #Autowired- and constructor-injection do not work with this by default, since these autowiring methods resolve the value immediately rather than using the property value resolution in AbstractAutowireCapableBeanFactory#applyPropertyValues. Autowiring by type will also not work, as type-resolution will not propagate through beans that are BeanDefinitions to find the produced type.
This method will only work if either of the two conditions are true:
The dependent beans are also defined in XML
Or if the autowire mode is set to AutowireCapableBeanFactory#AUTOWIRE_BY_NAME
<!-- Setting bean references through XML -->
<beans ...>
<bean id="myOtherBean" class="com.example.demo.ForkJoinPoolContainer">
<property name="forkJoinPool" ref="forkJoinPool" />
</bean>
</beans>
<!-- Or setting the default autowire mode -->
<beans default-autowire="byName" ...>
...
</beans>
Two additional changes could likely be made to enable constructor-injection and #Autowired-injection.
Constructor-injection:
The bean factory assigns an AutowireCandidateResolver for constructor injection. The default value (ContextAnnotationAutowireCandidateResolver) could be overridden (DefaultListableBeanFactory#setAutowireCandidateResolver) to apply a candidate resolver which seeks eligible beans of type BeanDefinition for injection.
#Autowired-injection:
The AutowiredAnnotationBeanPostProcessor bean post processor directly sets bean values without resolving BeanDefinition inner beans. This post processor could be overridden, or a separate bean post processor could be created to process a custom annotation for managed prototype beans (e.g., #AutowiredManagedPrototype).

Spring dependency injection controll

How do I control/restrict the instantiation of bean?
Lets say, I have 2 beans
A.java
B.java
Scopes of the both the bean as singleton & configured inside Spring application context
If A bean gets instantiated then B shouldn't vice-versa if B gets instantiated the A shouldn't.
You can use #Conditional or #Profile.
For first annotation you can write a class which will check if your bean exists.

Spring dynamic bean definition autowire

So first short introduction:
I have a working application context, now I want to create a new bean factory that extends it with some dynamic bean definitions.
So i create a new instance of DefaultListableBeanFactory passing base application context as parent.
Then I create a new bean definition:
BeanDefinition beanDef = BeanDefinitionBuilder.rootBeanDefinition(beanType)
.setScope(BeanDefinition.SCOPE_PROTOTYPE)
.setLazyInit(false)
.setAbstract(false)
.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_ALL)
.getBeanDefinition();
and at the end I register it with newly created bean factory
beanFactory.registerBeanDefinition(beanName, beanDef);
then some time later i would like to get new instance of that bean so I do:
Object beanInstance = beanFactory.getBean(jobType);
now i would expect that fields annotated with #Autowired are initialized.. but no. Calling beanFactory.autowireBean(beanInstance) does not help.
After looking up some other bean definitions in base application context i can see that my definitoin does not have any attributes and that I can add them by calling beanDef.setAttribute() but that requires me to know them in advance.
Now question. Is there a way to create fully initialized bean definition programmatically so it is autowired correctly?
So so i found out what i was missing:
AutowiredAnnotationBeanPostProcessor
it needs to be added to bean factory to fire up the #Autowired and #Value annotations.
also for #PostConstruct and #PreDestroy you need CommonAnnotationBeanPostProcessor
Bean factory created for application context by spring boot has total of 12 bean post processors so it is possible that some other are needed to get all features.

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 singleton scope-- per container per bean

I am asking this Question in reference to my question:
spring singleton scope
Spring singleton is defined in reference manual as per container per bean.
per container means if we do like:
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml")
MyBean myobj=(MyBean)context.getBean("myBean"); //myBean is of singleton scope.
MyBean myobj1=(MyBean)context.getBean("myBean");
Beans.xml:
<bean id="myBean" class="MyBean"/>
Then myobj==myobj1 will come out to true.Means both pointing to same instance.
For per bean part of phrase per container per bean i was somewhat confused. Am i right in following for per bean :
If we do like
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml")
MyBean myobj=(MyBean)context.getBean("myBean");
MyBean myobj1=(MyBean)context.getBean("mySecondBean");
Beans.xml:
<bean id="myBean" class="MyBean"/>
<bean id="mySecondBean" class="MyBean"/>
Then myobj==myobj1 will come out to false. Means then they are two different instances?
That is correct.
If it helps, you can also think of Spring beans as Instances that you would've otherwise created manually in your Java code using the constructor.
By defining the bean in the Spring XML file, that bean (Instance) gets registered with Spring's App Context and then that instance can be passed around to the other areas of the code.
By creating a new bean, you are effectively creating a new instance. So potentially you could create any number of beans (Instances) of the same class
myBean is a Spring singleton in the sense of every call to beans.getBean("myBean") will allways return the same instance. And mySecondBeanhaving a different id is another Spring singleton. You can have different singleton beans of same class in the same ApplicationContext .
Yes, you're right. Testing it would have told you.

Categories