By default, in Spring framework, 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 marking the bean definition as lazy-initialized.
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.
How to configure bean as lazy-initialized in Spring
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 on 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.
XML Configuration example for lazy initializing beans
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
You can run it using the following code.
<?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>
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 behaviour in Spring
If you want to make it a default behaviour at the container level that all the beans are lazy initialized 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 Java Configuration example for lazy initializing beans
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 Initializing Spring Beans. If you have any doubt or any suggestions to make please drop a comment. Thanks!
Related Topics
You may also like -