Autowiring is one of Spring’s most powerful features — just add @Autowired, and boom — your dependencies are injected. But have you ever wondered how this works under the hood?
In this article, we’ll peel back the layers and show you how Spring autowiring actually works internally — step by step, with examples, real internals, and best practices.
In this article, we will discuss a very important Spring dependency injection annotation that is a @Autowired…www.javaguides.net
What Is Autowiring?
Autowiring is Spring’s way of automatically resolving and injecting beans into your classes without you manually instantiating or wiring them.
@Service
public class OrderService {
@Autowired
private PaymentService paymentService;
}Here, Spring will scan for a PaymentService bean and inject it into OrderService. But how does this happen?
Step-by-Step: What Happens Internally?
1. Component Scanning and Bean Definitions
When your app starts, Spring performs component scanning (via @ComponentScan or @SpringBootApplication) and creates BeanDefinition objects for each annotated class (@Component, @Service, etc.).
At this point, OrderService and PaymentService are just definitions — they haven’t been created yet.
2. BeanPostProcessors Are Registered
Before beans are created, Spring registers a number of BeanPostProcessor implementations.
One of them is:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessorThis class is responsible for:
- Finding fields, constructors, or methods annotated with
@Autowired - Resolving dependencies
- Injecting the correct bean
3. Bean Instantiation Begins
When Spring decides it’s time to create a bean (e.g., OrderService), it goes through these phases:
- Constructor resolution
- Dependency injection
- Lifecycle callbacks
If you’ve annotated a constructor with @Autowired, Spring will resolve its arguments first:
@Service
public class OrderService {
private final PaymentService paymentService;
@Autowired
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}Spring resolves PaymentService from the container, injects it, and creates the object.
4. Field Injection (Reflection)
If you use field injection:
@Autowired
private PaymentService paymentService;Then AutowiredAnnotationBeanPostProcessor will:
- Use Java Reflection to find the field
- Check the type (
PaymentService) - Ask the container for a matching bean
- Use
field.setAccessible(true)to inject it manually
5. Handling Multiple Beans
If multiple candidates are found, Spring checks:
- If one is marked
@Primary - If one is explicitly marked via
@Qualifier
If ambiguity remains, Spring throws an error:
NoUniqueBeanDefinitionException6. Optional Dependencies
If a dependency is optional:
@Autowired(required = false)
private EmailService emailService;Spring will inject null if the bean doesn’t exist — and will not throw an error.
7. Lifecycle Continues
Once all dependencies are injected, Spring proceeds to:
- Call
@PostConstructmethods - Register the bean in the context
- Make it available to other beans
Under the Hood: Key Classes

Best Practices for Autowiring

📋 Summary Table

✅ Final Thoughts
Spring’s autowiring is magical — but under the hood, it’s just smart use of reflection, configuration metadata, and post-processors.
By understanding how @Autowired works internally, you can:
- Debug more effectively
- Write more predictable code
- Avoid hidden errors in large-scale applications
Autowiring is convenient. But with great power comes great responsibility — always use it with clarity and intent.
Comments
Post a Comment
Leave Comment