Monday, December 28, 2020

Lazy Initialization in Spring Using lazy-init And @Lazy Annotation

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

  1. How to Inject Prototype Scoped Bean in Singleton Bean
  2. Injecting Inner Bean in Spring
  3. Bean Scopes in Spring With Examples
  4. Wiring Collections in Spring
  5. Bean Definition Inheritance in Spring

You may also like-

  1. How to Read Properties File in Spring Framework
  2. @Conditional Annotation in Spring
  3. Configuring DataSource in Spring Framework
  4. Spring JdbcTemplate With ResultSetExtractor Example
  5. Encapsulation in Java
  6. Difference Between Checked And Unchecked Exceptions in Java
  7. Deadlock in Java multi-threading
  8. Introduction to Hadoop Framework

2 comments:

  1. Hi Anshudeep,

    Can 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.

    ReplyDelete
  2. I guess you are talking about circular dependency, if yes you can go through this post
    Circular Dependency in Spring Framework
    . Hope it helps.

    ReplyDelete