Close

Spring - Using @Lazy at Injection points

[Updated: Mar 24, 2017, Created: Jan 28, 2017]

Starting Spring 4.3, @Lazy can be used at injection points as well. That means we can place @Lazy along with @Autowired or @Inject or @Resource. That will delay the target bean initialization until it is used by the injection point class, even though the injection point class has been initialized earlier.


Example

We are registering two beans, MyEagerBean is by default eagerly initialized at startup, whereas, MyLazyBean is initialized lazily, that's because we are using @Lazy with factory method lazyBean().

public class MyConfig {

  @Bean
  public MyEagerBean eagerBean () {
      return new MyEagerBean();
  }

  @Bean
  @Lazy
  public MyLazyBean lazyBean () {
      return new MyLazyBean();
  }
}

Above usage of @Lazy annotation is what we learnt in the last tutorial.

Following is MyEagerBean which has an @Autowired annotation (an injection point). This bean will eagerly initialized and that will cause to initialize all it's dependencies as well, unless we use @Lazy at a given injection point:

public class MyEagerBean {

  @Autowired
  @Lazy
  private MyLazyBean myLazyBean;

  @PostConstruct
  public void init () {
      System.out.println(getClass().getSimpleName() + " has been initialized");
  }

  public void doSomethingWithLazyBean () {
      System.out.println("Using lazy bean");
      myLazyBean.doSomething();
  }
}

MyLazyBean:

public class MyLazyBean {

  @PostConstruct
  public void init () {
      System.out.println(getClass().getSimpleName() + " has been initialized");
  }

  public void doSomething () {
      System.out.println("inside lazy bean doSomething()");
  }
}

The main class:

public class LazyExampleMain {

  public static void main (String[] args) {
      ApplicationContext context =
                new AnnotationConfigApplicationContext(
                          MyConfig.class);
      System.out.println("--- container initialized ---");
      MyEagerBean bean = context.getBean(MyEagerBean.class);
      System.out.println("MyEagerBean retrieved from bean factory");
      bean.doSomethingWithLazyBean();
  }
}

Output

MyEagerBean has been initialized
--- container initialized ---
MyEagerBean retrieved from bean factory
Using lazy bean
MyLazyBean has been initialized
inside lazy bean doSomething()

Now if we comment out @Lazy from MyEagerBean:

public class MyEagerBean {

  @Autowired
  //@Lazy
  private MyLazyBean myLazyBean;
  .......
}

Output:

MyLazyBean has been initialized
MyEagerBean has been initialized
--- container initialized ---
MyEagerBean retrieved from bean factory
Using lazy bean
inside lazy bean doSomething()

When MyEagerBean is loaded, it will cause to initialize all it's dependencies unless we use @Lazy at injection point too. The usage of @Lazy in factory class MyConfig prevents loading bean during 'startup' until it's used first time in the application.

In short:

@Lazy with @Bean (or @Lazy with @Component): don't load eagerly during application start up, until it's used in the application

@Lazy with @Autowired : don't load during outer class initialization, until it's first used by the application.


How that works?

Spring creates and uses a lazy-resolution proxy object for the injection point (the one annotated with @Autowired and @Lazy) instead of initializing the object directly.


Example Project

Dependencies and Technologies Used:

  • spring-context 4.3.6.RELEASE: Spring Context.
  • JDK 1.8
  • Maven 3.3.9

Lazy Loading At Injection Point Example Select All Download
  • spring-lazy-injection-point
    • src
      • main
        • java
          • com
            • logicbig
              • example

See Also