By default, Spring ApplicationContext eagerly creates and initializes all ‘singleton scoped‘ beans during the application startup. In most cases, it helps detect the bean configuration issues at an early stage. But sometimes, we may need to mark some or all beans to be lazily initialized due to different project requirements.
1. @Lazy Initialization
Spring allows lazy beans creation in two ways:
- Applied to specific beans
- Configure the behavior globally
1.1. Only Specific Beans
To lazy load only specific beans, use @Lazy annotation along with @Bean annotation while declaring the bean.
@Configuration
public class AppConfig {
@Lazy
@Bean
public EmployeeManager employeeManager() {
return new EmployeeManagerImpl();
}
}
1.2. Global Configuration
To lazy load all beans, use @Lazy annotation along with @Configuration annotation at the class level.
@Lazy
@Configuration
public class AppConfig {
@Bean
public EmployeeManager employeeManager() {
return new EmployeeManagerImpl();
}
//other beans in this class are also lazy loaded
}
The above configurations are equivalent to the XML-based configuration‘s default-lazy-init=“true” attribute.
<beans default-lazy-init="true">
<bean id="operations" class="com.howtodoinjava.spring.beans.Operations"></bean>
</beans>
2. Autowiring @Lazy Beans
Generally, beans are injected into other components using @Autowired annotation. In this case, we must use the @Lazy annotation at both places:
- The bean definition which we want to lazy load
- The place it is injected along with @Autowired annotation
@Lazy
@Service
public class EmployeeManagerImpl implements EmployeeManager {
//
}
@Controller
public class EmployeeController {
@Lazy
@Autowired
EmployeeManager employeeManager;
}
Without using
@Lazyannotation at both places, autowiring will not work.
3. Demo
Let’s see the code of EmployeeManager, we are trying to lazy load.
//@Lazy -- Uncomment for lazy bean intializations
@Service
public class EmployeeManagerImpl implements EmployeeManager {
@Override
public Employee create() {
Employee emp = new Employee();
emp.setId(1);
emp.setName("Lokesh");
return emp;
}
@PostConstruct
public void onInit(){
System.out.println("EmployeeManagerImpl Bean is Created !!");
}
}
I have put the @PostConstruct annotation to detect when the bean is created. Let us initialize the application context with:
3.1. Without Lazy Loading
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("Bean Factory Initialized !!");
EmployeeManager empManager = ctx.getBean(EmployeeManager.class);
Employee emp = empManager.create();
Notice the program output. Here, the bean has been created and initialized before the bean factory is fully initialized.
EmployeeManagerImpl Bean is Created !!
Bean Factory Initialized !!
3.2. With Lazy Loading
Bean Factory Initialized !!
EmployeeManagerImpl Bean is Created !!
After enabling bean lazy loading, the bean factory is first fully initialized. Later when we requested the EmployeeManager bean, the factory then created the instance and returned it.
4. Conclusion
In this Spring tutorial, we learned about the basics of @Lazy annotation and how to use it for lazy bean initializations. we also saw an example of lazy loaded beans after the application context is fully initialized.
Drop me your questions in the comments section about the difference between lazy and eager loading in Spring.
Happy Learning !!
Hi Lokesh,
Suppose if I pass wrong properties to a bean,
<bean id="xyz" class="abc" lazy-init="true"> <property name="nonexistent" value="random"/> <!-- class abc has no nonexistent property --> </bean>And then don’t refer to this bean in the java code, why do I get error? If it was lazy initiated shouldn’t Spring IoC not bother about xyz bean while initializing ApplicationContext? And I should get error only when I try creating an object of abc class.
There will not be any error if this bean “xyz” is not passed as dependency into any other eager-initialized bean. In such case, to validate/initialize the eager-initialized bean, spring will initialize this lazy init bean as well.
If “xyz” bean is not used as dependency anywhere, then there will not be any error.
Hi Lokesh,
I am getting little confused after reading the first line of this blog which states that — “By default, Spring bean factory eagerly creates and initializes all ‘singleton scoped‘ beans during application startup itself.”
Consider below code, After execution of this code I am getting below output in console logs:
public class DrawingApp { public static void main( String[] args ) { System.out.println( "Hello World!" ); BeanFactory factory = new XmlBeanFactory(new FileSystemResource("spring.xml")); //<bean id="dummyObject" class="com.test.TestApplication" /> -- This is the only definition in spring.xml TestApplication testObject = (TestApplication) factory.getBean("dummyObject"); System.out.println("TestApplication Object hashCode :::: "+ testObject.hashCode()); } }Output:—–
Hello World!
Mar 02, 2018 11:21:20 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from file [D:\TUTORIAL\springcoretutorial\spring.xml]
TestApplication Object hashCode :::: 12122356
My question/confusion point is, after printing “Hello World!”, when getBean() method is called then it goes to load bean definition and then it provides result (which is lazy initialization). I don’t know my understanding is correct or not. Please put your comments.
Thanks
You have too sharp eyes. Thanks for catching it. Fact is that “
BeanFactoryuses lazy initialization approach whereasApplicationContextuses eager initialization approach” i.eBeanFactorycreates a singleton bean only when it is requested from it butApplicationContextcreates all singleton beans at the time of its own initialization.