14 - Spring Autowiring: Modes & Best Practices
- 11 - Creating Beans: @Component, @Service, @Repository, @Configuration & @Bean
- 12 - Understanding @PostConstruct and @PreDestroy
- 13 - Component Scanning Explained (@ComponentScan)
- 14 - Spring Autowiring: Modes & Best PracticesCurrent
- 15 - DispatcherServlet & Request Flow in Spring MVC
- 16 - Spring IoC Container Deep Dive
- 17 - Maven & Gradle Basics for Spring Boot
- 18 - Spring Boot Architecture Overview
- 19 - Key Spring Boot Annotations Explained
- 20 - Auto-Configuration in Spring Boot: How It Really Works
- 21 - Spring Boot Starters: Simplifying Dependency Management
- 22 - Spring Boot Configuration: application.properties & application.yml
Autowiring is the mechanism Spring uses to automatically resolve and inject dependencies between beans.
When used correctly, autowiring reduces boilerplate code and improves readability. When misused, it can cause ambiguity and runtime errors.
This post explains how autowiring works, the available modes, and best practices you should follow in real-world Spring Boot applications.
1. What Is Autowiring?
Autowiring allows Spring to automatically inject required dependencies into a bean without explicit configuration.
Instead of manually creating and wiring objects, Spring identifies the required dependencies and injects them at runtime using the IoC container.
2. Autowiring Modes in Spring
Spring supports multiple autowiring modes. Some are legacy (XML-based), while others are modern and annotation-based.
2.1 Constructor Injection (Recommended)
Dependencies are injected through the constructor.
@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
Why constructor injection is best:
- Makes dependencies explicit
- Ensures immutability
- Simplifies unit testing
- Prevents NullPointerException
- Preferred by Spring team
In Spring Boot 2+,
@Autowiredis optional for constructors with a single parameter.
2.2 Setter Injection
Dependencies are injected through setter methods.
@Service
public class NotificationService {
private EmailService emailService;
@Autowired
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
}
When to use:
- Optional dependencies
- Dependencies that may change
2.3 Field Injection (Not Recommended)
Dependencies are injected directly into fields.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}
Why avoid field injection?
- Hard to test
- Hides dependencies
- Breaks immutability
- Difficult to mock
Use it only in quick demos or legacy code.
3. Resolving Multiple Bean Candidates
If Spring finds more than one matching bean, it throws:
NoUniqueBeanDefinitionException
To resolve this, use:
3.1 @Qualifier
@Autowired
@Qualifier("paypalPaymentService")
private PaymentService paymentService;
3.2 @Primary
@Service
@Primary
public class DefaultPaymentService implements PaymentService { }
Spring will inject the primary bean by default.
4. Autowiring by Type vs Name
Spring resolves dependencies in this order:
- By Type
- By Qualifier
- By Bean Name
Understanding this order helps avoid injection conflicts.
5. Autowiring in Spring Boot
Spring Boot enhances autowiring by:
- Auto-configuring common dependencies
- Providing sensible defaults
- Reducing explicit configuration
Example:
@RestController
public class HelloController {
private final HelloService helloService;
public HelloController(HelloService helloService) {
this.helloService = helloService;
}
}
Spring Boot automatically injects HelloService without extra configuration.
6. Common Autowiring Pitfalls
❌ Multiple beans without qualifier
Always specify @Qualifier or @Primary.
❌ Using field injection everywhere
Prefer constructor injection.
❌ Circular dependencies
Refactor design or use setter injection if unavoidable.
❌ Injecting concrete classes instead of interfaces
Depend on abstractions, not implementations.
7. Best Practices
✔ Prefer constructor injection
✔ Use interfaces for dependencies
✔ Avoid field injection
✔ Use @Qualifier for multiple implementations
✔ Keep beans stateless when possible
These practices make applications cleaner, testable, and scalable.
8. Summary
- Autowiring automatically injects dependencies.
- Constructor injection is the recommended approach.
- Setter injection is useful for optional dependencies.
- Field injection should be avoided.
- Use
@Qualifierand@Primaryto resolve conflicts.
Proper autowiring is critical for clean Spring architecture.
What's Next?
Next post:
15 - DispatcherServlet & Request Flow in Spring MVC
We’ll explore how requests travel through Spring from controller to response.
