Spring @Lazy annotation in action

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.

Advertisement

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.

Facebooktwittergoogle_plusredditlinkedinmail
Advertisement

Leave a Reply