Spring @Lazy Annotation

Last Updated : 2 Feb, 2026

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.

Java
@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.

Java
@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.

Java
@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()
}

File Structure

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

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

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

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.

Application runs

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

Postman Output

Console Output:

Console Output

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

Comment

Explore