Bean Creation Life Cycle


1. Bean Creation Life Cycle in Spring

A Spring Bean is an object managed by the Spring IoC container. Its lifecycle goes through several stages:

Lifecycle Steps:

  1. Instantiation – Spring creates the bean (via constructor or factory method).
  2. Populate Properties – Dependencies are injected (setter/field/constructor injection).
  3. BeanNameAware / BeanFactoryAware – If implemented, Spring calls these awareness callbacks.
  4. Pre-initialization (BeanPostProcessor#postProcessBeforeInitialization) – Custom logic before initialization.
  5. Initialization – Runs after properties are set:
    • InitializingBean#afterPropertiesSet() (if implemented)
    • @PostConstruct method (if annotated)
    • Custom initMethod (if configured in @Bean(initMethod=...) or XML)
  6. Post-initialization (BeanPostProcessor#postProcessAfterInitialization) – Wrapping/proxies applied.
  7. Bean in Use – Application can use the bean.
  8. Destruction – When context is closed:
    • DisposableBean#destroy() (if implemented)
    • @PreDestroy (if annotated)
    • Custom destroyMethod (if configured)

Example: Bean Lifecycle

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Component;

@Component
public class MyService {

    public MyService() {
        System.out.println("1. Bean Instantiated");
    }

    @PostConstruct
    public void init() {
        System.out.println("2. @PostConstruct called - Initialization");
    }

    public void doWork() {
        System.out.println("3. Bean in use");
    }

    @PreDestroy
    public void cleanup() {
        System.out.println("4. @PreDestroy called - Cleanup before destroy");
    }
}

2. Qualifier Annotations in Spring

When multiple beans of the same type exist, Spring cannot auto-wire by type. To resolve ambiguity, we use @Qualifier.

Example without @Qualifier (will cause error):

import org.springframework.stereotype.Component;

@Component
public class EmailService implements MessageService {
    public String sendMessage() { return "Email message sent!"; }
}

@Component
public class SMSService implements MessageService {
    public String sendMessage() { return "SMS message sent!"; }
}
@Component
public class Notification {

    // ERROR: Multiple beans of type MessageService
    private final MessageService messageService;

    public Notification(MessageService messageService) {
        this.messageService = messageService;
    }
}

Example with @Qualifier

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class Notification {

    private final MessageService messageService;

    public Notification(@Qualifier("emailService") MessageService messageService) {
        this.messageService = messageService;
    }

    public void notifyUser() {
        System.out.println(messageService.sendMessage());
    }
}

Example with Custom Qualifier Annotation

You can also create a custom qualifier:

import org.springframework.beans.factory.annotation.Qualifier;

import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface SMS {
}

Use it like:

@SMS
@Component
public class SMSService implements MessageService {
    public String sendMessage() { return "SMS message sent!"; }
}

@Component
public class Notification {

    private final MessageService messageService;

    public Notification(@SMS MessageService messageService) {
        this.messageService = messageService;
    }
}

Summary:

  • Bean lifecycle = instantiation → dependency injection → initialization → use → destruction.
  • Qualifier annotations (@Qualifier or custom ones) resolve ambiguity when multiple beans of the same type exist.

Leave a Reply