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)@PostConstruct
method (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 (
@Qualifier
or custom ones) resolve ambiguity when multiple beans of the same type exist.