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:
- Instantiation – Spring creates the bean (via constructor or factory method).
- Populate Properties – Dependencies are injected (setter/field/constructor injection).
- BeanNameAware / BeanFactoryAware – If implemented, Spring calls these awareness callbacks.
- Pre-initialization (
BeanPostProcessor#postProcessBeforeInitialization) – Custom logic before initialization. - Initialization – Runs after properties are set:
InitializingBean#afterPropertiesSet()(if implemented)@PostConstructmethod (if annotated)- Custom
initMethod(if configured in@Bean(initMethod=...)or XML)
- Post-initialization (
BeanPostProcessor#postProcessAfterInitialization) – Wrapping/proxies applied. - Bean in Use – Application can use the bean.
- 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 (
@Qualifieror custom ones) resolve ambiguity when multiple beans of the same type exist.
