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. |
This might be another way to resolve cold start issues in AWS Lambda
Nice written article. Good job!
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 »
Hi Valention. Thank you for your comment. I’ve just recreated the case you mentioned to check if something has changed in Spring. But even with the latest Spring Boot the lazy dependency initialization still works as I described in the post. When Spring creates the instance of the RootResource class, the provided non-empty constructor is called with a proxy object of the LazyResource class as the parameter. Spring generates the proxy object dynamically at the runtime using CGLIB. The proxy creates the actual object it mimics when one of its real methods is called. I don’t know why it doesn’t… Read more »
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
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.
Glad to hear you solved the issue and everything is working now as you expect.
The valuable takeaway from your story is that we should pay more attention on beans which we want to load with the lazy mechanism. Especially, if we want to apply the mechanism in an existing application where beans are used in several different places.
Thank you for sharing this Valentino!
Hey everyone!
I facing the problem that i can
t understand.
s own state of SESSIONHow @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 bean, when SESSION
s bean service called from an APPLICATION scoped bean.My question is HOW does it work
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