In Spring, beans are by default created eagerly at application startup, which can slow down the application if some beans are heavy or rarely used. The @Lazy annotation allows beans to be initialized only when they are first needed, improving performance and optimizing resource usage. This is particularly useful for:
- Beans that are expensive to create.
- Beans that may not be needed immediately.
- Reducing application startup time.
Usage of @Lazy
@Lazy can be used in different contexts in Spring:
1. On a Bean Definition
You can mark a bean as lazy directly in the configuration class.
@Configuration
public class AppConfig {
@Bean
@Lazy
public ExpensiveService expensiveService() {
return new ExpensiveService();
}
}
Explanation: The ExpensiveService bean will not be instantiated at application startup. It will be created only when it is first requested.
2. On a Component Class
You can also use @Lazy on a Spring component.
@Component
@Lazy
public class LazyComponent {
public LazyComponent() {
System.out.println("LazyComponent initialized");
}
}
Explanation: The LazyComponent will not be initialized during startup but only when injected or requested from the context.
3. On Injection Points
@Lazy can be used at the injection point of a dependency to lazily inject a bean.
@Component
public class ClientService {
private final ExpensiveService expensiveService;
public ClientService(@Lazy ExpensiveService expensiveService) {
this.expensiveService = expensiveService;
}
public void useService() {
expensiveService.execute();
}
}
Explanation: ExpensiveService will only be created when useService() is called, not when ClientService is initialized.
Steps to Implement @Lazy Annotation in Spring Boot
Step 1: Add Required Dependencies
Create a new Spring Boot project using Spring Initializr and add the following dependencies:
- Spring Web
- Lombok
- Spring Boot DevTools
build.gradle:
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.4'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'org.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}tasks.named('test') {
useJUnitPlatform()
}

Step 2: Create a Time-Consuming Bean
This bean simulates a resource-heavy initialization process and is annotated with @Lazy, so it will only be created when first accessed.
File: src/main/java/org/example/lazydemo/bean/TimeConsumingBean.java
package org.example.lazydemo.bean;
import jakarta.annotation.PostConstruct;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
@Lazy
public class TimeConsumingBean {
@PostConstruct
public void init() {
try {
Thread.sleep(5000); // Simulate time-consuming initialization
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("TimeConsumingBean initialized!");
}
public void doSomething() {
System.out.println("Executing logic in TimeConsumingBean...");
}
}
- @Component registers the bean with the Spring container.
- @Lazy ensures the bean is not created at startup.
- The @PostConstruct method simulates a delay to represent a heavy initialization process.
Note: The @PostConstruct log message is not visible at application startup because the bean is lazily initialized and created only when the /action endpoint is accessed.
Step 3: Create a Controller
The controller will trigger the lazy initialization of the bean when the endpoint is accessed.
File: src/main/java/org/example/lazydemo/controller/MyController.java
package org.example.lazydemo.controller;
import org.example.lazydemo.bean.TimeConsumingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
public class MyController {
@Autowired
private TimeConsumingBean timeConsumingBean;
@GetMapping("/action")
public String performAction() {
timeConsumingBean.doSomething();
return "Action performed!";
}
}
When the /action endpoint is called, Spring will create the TimeConsumingBean instance for the first time (triggering its initialization).
Step 4: Main Application Class
File: src/main/java/org/example/lazydemo/LazyDemoApplication.java
package org.example.lazydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LazyDemoApplication {
public static void main(String[] args) {
SpringApplication.run(LazyDemoApplication.class, args);
}
}
This class is the entry point for the Spring Boot application.
Step 5: Run and Test the Application
Run the application using the command:
./gradlew bootRun
or from your IDE as a Spring Boot app.

The application will start quickly, even though the TimeConsumingBean takes 5 seconds to initialize because it hasn’t been created yet.
Now, open Postman or your browser and send a GET request:
GET: http://localhost:8080/action
Console Output:

The bean initializes only when accessed for the first time, confirming lazy initialization is working correctly.
