In Spring framework, by default all the singleton beans are eagerly created and configured by ApplicationContext as part of the initialization process. Though this behavior of pre-instantiation is desirable most of the time as you can detect errors in the configuration immediately. But sometimes you may have a large object graph and loading all those beans in the beginning itself may be expensive. In that kind of scenario you can prevent pre-instantiation of a singleton bean by configuring the Spring bean to be initialized lazily.
If you mark a bean as lazy-initialized in Spring that means IoC container will create a bean instance when it is first requested, rather than at startup.
Here note that when a lazy-initialized bean is a dependency of a singleton bean that is not lazy initialized, the ApplicationContext creates the lazy-initialized bean at startup, because it must satisfy the singleton’s dependencies.
Configuration for lazy initialization of Spring beans
You can configure bean as lazy-initialized in both XML based configuration and Java based configuration.
- In XML configuration you need to add lazy-init attribute to the <bean/> element.
- In case of Java configuration you need to use @Lazy annotation.
Let’s see Spring example for both these type of configurations.
Spring bean lazy initialization using lazy-init example
In this example there are two beans PayServiceImpl and CashPayment. For PayServiceImpl bean lazy-init attribute is true.
Interface IpayService
public interface IPayService { void performPayment(); }
PayServiceImpl.java
import javax.annotation.PostConstruct; public class PayServiceImpl implements IPayService{ private IPayment payment; public PayServiceImpl(){ } public PayServiceImpl(IPayment payment){ this.payment = payment; } public void performPayment() { System.out.println("performPayment Method called"); } @PostConstruct public void annoInitMethod(){ System.out.println("Calling InitMethod for PayServiceImpl"); } public IPayment getPayment() { return payment; } public void setPayment(IPayment payment) { this.payment = payment; } }
CashPayment.java
import javax.annotation.PostConstruct; public class CashPayment implements IPayment{ public void executePayment() { System.out.println("Perform Cash Payment "); } @PostConstruct public void annoInitMethod(){ System.out.println("Calling InitMethod for CashPayment"); } }
In these classes you can see that Spring bean life cycle initialization method annotated with @PostConstruct is used to see when bean is actually initialized.
XML Configuation
In the XML configuration, to lazy initialize payServiceBean, attribute lazy-init is set as true.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" /> <!-- Defining PayServiceImpl bean --> <bean id="payServiceBean" class="org.netjs.exp.Spring_Example.PayServiceImpl" lazy-init="true"/> <bean id="cashPaymentBean" class="org.netjs.exp.Spring_Example.CashPayment" /> </beans>You can run it using the following code.
public class App { public static void main( String[] args ){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("appcontext.xml"); System.out.println("Loading app context"); IPayService bean = (IPayService) context.getBean("payServiceBean"); } }
Output
INFO: Loading XML bean definitions from class path resource [appcontext.xml] Calling InitMethod for CashPayment Loading app context Calling InitMethod for PayServiceImpl
You can see that the CashPayment bean which is not lazy-initialized is initialized while loading the XML bean definitions where as PayServiceImpl bean is initialized when it is first requested.
Making lazy initialized default behavior in Spring
If you want to make lazy initialization of beans a default behavior at the container level then you can add default-lazy-init attribute on the <beans/> element; for example:
<beans default-lazy-init="true"> <!-- no beans will be pre-instantiated... --> <bean>bean definitions </bean> </beans>
Spring bean lazy initialization using @Lazy annotation
If we use the same two classes as above PayServiceImpl and CashPayment. Then the Java config class where PayServiceImpl bean is marked as lazy will look like as follows.
import org.netjs.exp.Spring_Example.CashPayment; import org.netjs.exp.Spring_Example.IPayService; import org.netjs.exp.Spring_Example.IPayment; import org.netjs.exp.Spring_Example.PayServiceImpl; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; @Configuration public class AppConfig { @Bean @Lazy public IPayService payService(){ PayServiceImpl payServiceImpl = new PayServiceImpl(); return new PayServiceImpl(cashPayment()); //return null; } @Bean public IPayment cashPayment(){ return new CashPayment(); } }
Here note @Lazy annotation is used to mark PayServiceImpl as lazy initialized.
To run it you can use the following code.
import org.netjs.exp.Spring_Example.IPayService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.AbstractApplicationContext; public class App { public static void main( String[] args ){ AbstractApplicationContext context = new AnnotationConfigApplicationContext( AppConfig.class); System.out.println("Loading AnnotationConfig app context"); IPayService bean = (IPayService) context.getBean("payService"); context.close(); } }
output
Calling InitMethod for CashPayment Loading AnnotationConfig app context Calling InitMethod for PayServiceImpl
Here again you can see that the CashPayment bean which is not lazy-initialized is initialized while loading the bean definitions where as PayServiceImpl bean is initialized when it is first requested.
If you want to lazy initialized all the beans then use the annotation @Lazy at the class level.
@Configuration @Lazy public class AppConfig { .. .. }
That's all for this topic Lazy Initialization in Spring Using lazy-init And @Lazy Annotation. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Spring Tutorial Page
Related Topics
You may also like-
Hi Anshudeep,
ReplyDeleteCan you provide solution for below scenario
Class A{
@Autowire
B b;
}
Class B{
@Autowire
A a;
}
In the above scenario,
-> How spring ioc will initialize the beans.
-> Which bean will create first A or B
Thanks in Advance.
I guess you are talking about circular dependency, if yes you can go through this post
ReplyDeleteCircular Dependency in Spring Framework. Hope it helps.