Enterprise Java

Spring @Lazy annotation use cases

The Spring framework with almost no effort can solve for you many common programming problems, but some of its features are less known than others. In this post, we’re going to take a close look at the @Lazy annotation, which belongs to this group. After reading several examples, you should be able to apply the annotation to your daily development tasks.

1. @Lazy bean initialization

The default behavior of Spring is to create all defined beans at the startup of the application. If we consider the fact that such initialization can be quite time consuming, it seems reasonable to execute heavy operations before users start to burden our server.

But do we really always need all application components loaded into memory? You probably heard about the Pareto principle and the fact it applies to software development as well. After identification of less used features, it’s worth to consider lazy initialization for connected beans, especially if they consume valuable resources.

How to make a bean lazy? There are two options depending on the way such bean is declared. If the declaration is in a @Configuration class using the @Bean annotation, you just have to mark it with the @Lazy annotation:

@Configuration
class SomeConfig {

   @Lazy
   @Bean
   LazyResource lazyResource() {
       return new LazyResource();
   }

}

If the bean uses one of component annotations and is discovered by the component scanning process, the @Lazy annotation can be used directly in the bean class:

@Lazy
@Component
class LazyResource {
   //...
}

@Lazy can also be used directly on a @Configuration class. In that case, all @Bean objects defined in the class are lazily initialized.

It’s worth remembering that marking a bean with @Lazy doesn’t mean its dependencies are also lazy initialized. If you’re interested in lazy bean graph initialization, you can achieve it with…

2. @Lazy injection – delaying bean creation to first use

Next to bean definitions, the @Lazy annotation can also be used for injection points like constructors, constructor’s parameters, fields and setters. Below there is an example of lazy injection on a whole constructor (@Autowired annotation omitted since no longer required since Spring 4.3), which means all defined dependencies will be affected by the annotation.

@Component
class RootResource {

   private final ResourceDependency dependency;

   @Lazy
   RootResource(ResourceDependency dependency) {
       this.dependency = dependency;
   }

}

No matter which injection method you use, in all cases instead of a reference to a real dependency, a proxy object is provided.

It’s important to understand that if a relation is marked with @Lazy it doesn’t mean that creation of the dependent bean is postponed. When the dependent bean isn’t marked with @Lazy itself, it will be eagerly created by the Spring container. Such behavior leads to the conclusion that lazy injection should be mainly used together with lazy initialization.

Let’s consider an example in which there are two related beans. The first bean is marked with @Lazy:

@Lazy
@Component
class LazyResource {
   //...
}

The other bean which is eagerly initialized depend on the first one, but the injection point is marked as @Lazy:

@Component
class RootResource {

   private final LazyResource dependency;

   @Lazy
   RootResource(LazyResource dependency) {
       this.dependency = dependency;
   }

   void useLazyDependency() {
       dependency.use();
   }

}

In the described scenario, when a new instance of the RootResource class is created, its dependency isn’t initialized. The new instance of LazyResource is built when it’s actually needed. In this example, it’s the moment when the useLazyDependency() method is called for the first time. By removing @Lazy from RootResource’s constructor, the initialization of the LazyResource bean would have to be executed prior to injection.

3. Solving circular dependencies with @Lazy injection

Circular dependencies in applications are considered rather as a bad design pattern, but if you don’t see any alternative solution to a problem you’re facing, lazy injection may come in handy.

Once you try to create a cycle between two beans, Spring will inform you about such problem with a message similar to the one presented below:

The dependencies of some of the beans in the application context form a cycle:
┌─────┐
|  peerResource defined in file [...\dolszewski\blog\PeerResource.class]
↑     ↓
|  someResource defined in file [...\dolszewski\blog\SomeResource.class]
└─────┘

In order to solve the issue, beans don’t have to be lazy initialized. The @Lazy annotation is required only on one of injection points. The one which marks its dependency as lazy will be created first.

4. Eager beans with @Lazy(false)

Although the first association with the @Lazy annotation is possibility to create beans on demand, it also allows to achieve the opposite effect – eager initialization. When you meet the @Lazy annotation and learn about its existence, it is very likely that you don’t notice that it can actually accept additional boolean attribute which indicates whether lazy initialization should occur.

Your second thought might be that using @Lazy(false) is actually useless as you can simply remove the annotation to achieve the same, right? If you consider simple default behavior of Spring, it’s absolutely correct, but life isn’t always that simple.

When your application’s startup is really slow, you may consider lazy initialization for all managed beans to improve your development experience. Yet, sometime there are beans which should always be initialized, even if eager initialization has been globally disabled with @ComponentScan(lazyInit = true). That’s when @Lazy(false) comes in.

@Lazy(false)
@Component
class AlwaysEagerResource {
   //...
}

Conclusion

Familiarization with the @Lazy annotation isn’t very demanding as it accepts only one attribute and can be applied only in a few places. However, considering its several uses, it’s worth to be aware about its existence. If you find the article useful, please share it with your colleagues and co-workers. Do you know any other useful tricks in which @Lazy plays one of the main roles? If you do, don’t hesitate to put them in a comment.

Published on Java Code Geeks with permission by Daniel Olszewski, partner at our JCG program. See the original article here: Spring @Lazy annotation use cases

Opinions expressed by Java Code Geeks contributors are their own.

Daniel Olszewski

Daniel Olszewski is a software developer passionate about the JVM ecosystem and web development. He is an advocate of clean, maintainable, and well tested code
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

9 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Tristan D.
Tristan D.
6 years ago

This might be another way to resolve cold start issues in AWS Lambda

Krystian
Krystian
6 years ago

Nice written article. Good job!

Valentino Pezzano
Valentino Pezzano
6 years ago

Hi Daniel. At a certain point, you have this scenario: @Lazy @Component class LazyResource { //… } @Component class RootResource { private final LazyResource dependency; @Lazy RootResource(LazyResource dependency) { this.dependency = dependency; } void useLazyDependency() { dependency.use(); } } and you say “In the described scenario, when a new instance of the RootResource class is created, its dependency isn’t initialized. The new instance of LazyResource is built when it’s actually needed.” If I write explicitly the empty constructor in LazyResource, and put a print in the constructor, running the example I can see the invocation of the LazyResource instance, and… Read more »

Valentino Pezzano
Valentino Pezzano
6 years ago

Hi Daniel. First of all, let me tell you thanks a lot for looking at this.
I was looking at this behavior inside a Spring Boot application, which is this one:
https://github.com/vpezzano/spring-actuator

Now, inside the package com.javacodegeeks.laziness.bean
there are the 2 classes RootResourceWithLazyInjection and LazyResourceDependency.
As I am not calling the method useDependency() in RootResourceWithLazyInjection, I would expect not to see in the console the print I’ve put in the construtor of LazyResourceDependency, but I see this print, so I don’t get where the twist is.
Thanks again.
Valentino

Valentino
Valentino
6 years ago

Figured out what the issue was, in the constructor of RootResourceWithLazyInjection, I reference the dependency LazyResourceDependency, and this forces the creation of an instance of it. If I remove this reference from the constructor of RootResourceWithLazyInjection, I can actually see that the dependency is created only when it’s referenced later on. So, what you said is correct, and I was using things in the wrong way.

Alexander
Alexander
5 years ago

Hey everyone!
I facing the problem that i cant understand.
How @Lazy annotation would affect injection of SESSION scoped bean, in APPLICATION scoped bean.
I mean I tested what would happen - each session would have it
s own state of SESSIONs bean, when SESSIONs bean service called from an APPLICATION scoped bean.
My question is HOW does it work

Agustin
Agustin
2 years ago

Hi Daniel !. First of all… Thanks for the article !. I would like to ask you the following: I used the approach with @Lazy and the mongo initialization beans are not created (which is what I wanted). The thing is that, while executing a request to a controller and while doing nothing, that seems to trigger the mongo initialization logics… I would like that to be executed only while using he mongo repository or executing an operation against the database… Am I clear ?… Thanks a lot bro

Back to top button