Spring series, part 3: @Lazy

Lazy initialization allows for a greater flexibility and performance by delaying bean instantiation to the very last moment. A fairly straightforward feature represented by a simple annotation @Lazy. Yet, as usual, there are a few pitfalls to watch out for.
Let's start with some trivia. Adding @Lazy on the class level is all it takes to prevent the bean to be initialized when the application starts up:
 import org.springframework.context.annotation.Lazy;  
 import org.springframework.context.annotation.Bean;  
 ..  
 @Bean  
 @Lazy  
 public class Foo {  
 ..  
 }  
More interestingly though, a whole configuration suite can be handled all at once:
import org.springframework.context.annotation.Configuration;  
..  
@Configuration  
@Lazy  
public class AppConf {  
   
  // All of the beans below are subject of a lazy load  
   
  @Bean  
  public BeanA beanA() {  
   return new BeanA();  
  }  
   
  @Bean  
  public BeanB beanB() {  
   return new BeanB();  
  }  
  ..  
}  
There is an exception to every rule and sooner or later you are going to appreciate the option of stating the contradictory @Lazy(value = false):
 @Configuration  
 @Lazy  
 public class AppConf {  
  // An eagerly loaded bean  
  @Bean  
  @Lazy(value = false)  
  public BeanC beanC() {  
   return new BeanC();  
  }  
  ..  
 }  
Obviously, a prototype is lazy by default:
 import org.springframework.context.annotation.Scope;  
  ..  
  // No need to use @Lazy  
  @Bean  
  @Scope(value = "prototype")  
  public class MyBean {  
   ..  
  }  
Now it's on time to tackle the downside. First and foremost, think dependencies:
 @Bean  
 @Lazy  
 public class Foo {  
 }  
    
 @Bean  
 public class Bar {  
  @Autowired  
  private Foo foo;  
 }  
Foo is bound to be eagerly loaded since the singleton Bar depends on it:
 Processing injected method of bean 'bar': AutowiredFieldElement for private Foo Bar.foo  
 Creating shared instance of singleton bean 'foo'  
Next, lazy loading doesn't really work when @Primary is around. I briefly talked about this problem in one of my previous posts. Let's set a quick example:
 public interface IOrdinal {  
 }  
 import org.springframework.context.annotation.Primary;  
   
 @Component  
 @Primary  
 public class TheFirst implements IOrdinal {  
 }  
 import org.springframework.context.annotation.Lazy;  
   
 @Component  
 @Lazy  
 public class TheSecond implements IOrdinal {  
 }  
 import org.springframework.context.annotation.Scope;  
   
 @Component  
 @Scope(value = "prototype")  
 public class TheThird implements IOrdinal {  
 }  
Out of the three implementations of the interface IOrdinal, one is lazily loaded and the other is a prototype. Both of which thus should be excluded from the pre-initialization process. This rule is however broken by declaring TheFirst as primary.

Taking advantage of the default dependency injection..
 ..  
  // Injects TheFirst  
  @Autowired  
  private IOrdinal ordinal;  
 ..  
.. comes at a price of a complete eager load
 Returning cached instance of singleton bean 'theFirst'  
 Creating instance of bean 'theSecond'  
 Eagerly caching bean 'theSecond' to allow for resolving potential circular references  
 Finished creating instance of bean 'theSecond'  
 Creating instance of bean 'theThird'  
 Finished creating instance of bean 'theThird'  
That's it for today. Next time, I will look into the various types of Spring components and the distinction between a @Component and a @Bean.

If you happen to follow my examples on github make sure you check the unit tests covering this chapter where you find an application of grep4j. I talked about this useful tool in detail in one of my older posts.

Source Code

Previous: Part 2 - @Qualifier and @Resource Next: Part 4 - @Lazy on injection points