@Autowired
About
In the Spring Framework, @Autowired is an annotation used for automatic dependency injection. It tells Spring to resolve and inject a bean into the marked field, constructor, or method based on the bean’s type, without requiring explicit configuration in XML or Java configuration classes.
Spring performs this injection at runtime by scanning the application context for a matching bean. If exactly one bean of the required type exists, it is injected automatically. If more than one candidate exists, Spring requires additional disambiguation - typically via @Primary, @Qualifier, or by matching bean names.
@Autowired is used whenever a class depends on another Spring-managed bean, and we want Spring to handle the wiring without manual instantiation. It promotes loose coupling and easier testing by allowing bean dependencies to be defined declaratively rather than imperatively in code.
Attributes
The @Autowired annotation has one primary attribute and one meta-behavior that affects how it interacts with the injection process.
required
boolean
true
Indicates whether the dependency is mandatory. If true and no suitable bean is found, Spring throws an exception. If false, Spring will inject null (for objects) or the default value (for primitives/wrappers).
Attribute Details
required
Default behavior (
true):If no bean of the required type (or matching qualifiers) exists in the application context, Spring throws a
NoSuchBeanDefinitionExceptionduring context initialization.Ensures the application fails fast when a critical dependency is missing.
Optional injection (
false):The annotated field, parameter, or method argument can remain unset if no candidate is found.
Commonly used when injecting optional collaborators or when certain beans are only conditionally loaded.
Useful for plugin-based or feature-flag-driven systems.
Caution: Optional injection may lead to
NullPointerExceptionif we forget to check fornullbefore using the dependency.
Meta-Behavior
@Autowired as a meta-annotation
While @Autowired itself has only required as a configurable attribute, its behavior is influenced by other annotations when combined:
With
@Qualifier: Narrows bean selection when multiple candidates exist.With
@Lazy: Delays bean instantiation until the dependency is first accessed.With
@Primary: Selects a default candidate when multiple matches exist.
How It Works ?
The @Autowired annotation triggers Spring’s dependency resolution and injection process during the bean creation phase of the application context lifecycle.
At a high level, Spring’s AutowiredAnnotationBeanPostProcessor detects @Autowired annotations on bean fields, constructors, and methods, and then attempts to resolve and inject a suitable bean from the application context.
Step-by-Step Internal Process
1. Bean Scanning and Detection
When Spring starts, it scans our classes for annotations like
@Component,@Service,@Controller, and@Configuration(or beans defined via XML/Java config).It also registers BeanPostProcessors, including
AutowiredAnnotationBeanPostProcessor, which specifically looks for@Autowired(and similar annotations like@Inject).
2. Identifying Injection Points
For each bean being created, the post-processor:
Inspects all fields, constructors, and methods.
Marks those annotated with
@Autowiredas injection points.Tracks metadata so the injection can be performed after the bean is instantiated but before it’s used.
3. Injection Type Resolution
Spring matches dependencies by type first:
Single Match → Inject directly.
Multiple Matches → Apply narrowing rules in order:
@Qualifiermatch (if present at injection point).Bean name match (field name or parameter name matches a bean id).
@Primarypreference (if exactly one primary exists).
No Match →
If
required=true, throwNoSuchBeanDefinitionException.If
required=false, injectnull(or default primitive value).
4. Constructor Injection Priority
If a bean has a single constructor, Spring will use it for injection automatically (even without
@Autowired).If multiple constructors exist, we must annotate exactly one with
@Autowiredso Spring knows which one to use.Constructor injection ensures all required dependencies are available at instantiation time, making the bean immutable after creation.
5. Field Injection Mechanics
Spring uses reflection to set private/protected/public fields.
Field injection happens after the bean is constructed but before any
@PostConstructmethods run.This approach is convenient but makes dependencies less explicit — constructor injection is often preferred in complex systems.
6. Method (Setter) Injection Mechanics
Spring identifies setter methods (or arbitrary methods) annotated with
@Autowired.Parameters are resolved like constructor parameters — by type first, then by qualifier/name.
Useful for optional dependencies that may change or for legacy beans needing backward-compatible wiring.
7. Handling Optional Dependencies
If a dependency is optional, we can:
Set
@Autowired(required=false)
8. Circular Dependency Handling
For singleton beans, Spring can resolve circular dependencies between fields and setters via early references from the singleton cache.
However, constructor-based circular dependencies are not resolvable and will cause a
BeanCurrentlyInCreationException.Avoiding circular dependencies is generally recommended - it indicates tight coupling between components.
9. Lazy Injection
If combined with
@Lazy, the dependency is injected as a proxy, and the target bean is created only when first used.This can break dependency cycles or reduce startup time for expensive beans.
Best Practice
Correct usage of @Autowired can greatly improve code clarity and maintainability, while poor usage can lead to brittle, tightly coupled systems. The following guidelines help ensure @Autowired is used effectively in production applications.
1. Prefer Constructor Injection Over Field Injection
Why: Constructor injection makes dependencies explicit, supports immutability, and allows for easier unit testing without reflection.
Spring automatically injects a single constructor without needing
@Autowired, but adding it explicitly improves readability.Example:
@Component
class OrderService {
private final PaymentService paymentService;
@Autowired
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}2. Avoid Field Injection in Complex Systems
Field injection is convenient for quick prototypes but hides dependencies, making code harder to test and refactor.
If we must use field injection (e.g., in legacy beans or configuration classes), keep it to simple, non-critical dependencies.
3. Keep Dependencies Minimal
If a bean requires many
@Autowireddependencies, it may be violating the Single Responsibility Principle.Consider splitting the bean into smaller components with clearer purposes.
4. Use @Qualifier When Multiple Beans Exist
@Qualifier When Multiple Beans ExistWhen multiple beans of the same type exist, always disambiguate with
@Qualifieror@Primary.This avoids accidental bean resolution changes if another bean of the same type is introduced later.
5. Avoid Circular Dependencies
Circular dependencies indicate strong coupling and make code harder to maintain.
If unavoidable, use setter injection or
@Lazyinjection to break the cycle but redesign is usually the better fix.
6. Use @Lazy for Expensive Beans
@Lazy for Expensive BeansIf a dependency is costly to initialize or rarely used, annotate it with
@Lazyto defer creation until needed.This can speed up application startup and reduce memory footprint.
7. Limit @Autowired Usage in Configuration Classes
In
@Configurationclasses, prefer constructor injection for dependencies rather than field injection.This ensures all dependencies are ready before bean creation and avoids subtle lifecycle issues.
8. Do Not Overuse @Autowired
@AutowiredUse it for true dependencies, not just for convenience to access a bean.
If a dependency can be passed as a method argument or handled locally, avoid injecting it.
9. Test Dependency Wiring Explicitly
For integration tests, ensure the Spring context loads with the intended dependencies wired in.
Use
@MockBeanor@TestConfigurationto override dependencies in test scenarios without affecting production beans.
10. Handle Optional Dependencies Safely
Instead of
@Autowired(required=false), prefer:Optional<T>injection (since Spring 4.3)@Nullableinjection (since Spring 5.0)
These approaches make optionality explicit and reduce null-handling errors.
Example
1. Field Injection (Basic Usage)
@Component
class OrderService {
@Autowired
private PaymentService paymentService;
public void processOrder() {
paymentService.pay();
}
}Explanation
Spring finds a bean of type
PaymentServiceand injects it into the private field, even without a setter or constructor.Convenient for small projects, but hides dependencies (less test-friendly).
2. Constructor Injection (Preferred)
@Component
class OrderService {
private final PaymentService paymentService;
@Autowired
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}Explanation
Dependencies are made explicit and required at bean creation time.
If there’s only one constructor, Spring can inject it without the
@Autowiredannotation, but adding it makes intent clear.
3. Multiple Constructor Scenario
@Component
class OrderService {
private final PaymentService paymentService;
@Autowired
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public OrderService() {
this.paymentService = null;
}
}Explanation
If multiple constructors exist, we must annotate the one we want Spring to use.
Without
@Autowired, Spring cannot decide which constructor to use.
4. Setter Injection
@Component
class OrderService {
private PaymentService paymentService;
@Autowired
public void setPaymentService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}Explanation
Useful when we want to inject dependencies after object creation, or when they are optional.
More flexible, but less strict than constructor injection.
5. With @Qualifier to Resolve Ambiguity
@Qualifier to Resolve Ambiguity@Component
class OrderService {
@Autowired
@Qualifier("fastPaymentService")
private PaymentService paymentService;
}Explanation
When multiple beans implement
PaymentService,@Qualifierensures the correct one is injected.Without this, Spring throws
NoUniqueBeanDefinitionException.
6. Optional Dependency with required=false
required=false@Component
class OrderService {
@Autowired(required = false)
private DiscountService discountService;
}Explanation
If
DiscountServicebean doesn’t exist, no error is thrown;discountServicewill benull.Risk: Must check for null before use.
7. Optional Dependency with Optional<T>
Optional<T>@Component
class OrderService {
@Autowired
private Optional<DiscountService> discountService;
}Explanation
Since Spring 4.3,
Optionalinjection avoids null checks.Use
discountService.ifPresent(...)to safely run code when the bean exists.
8. Optional Dependency with @Nullable
@Nullable@Component
class OrderService {
@Autowired
public void setDiscountService(@Nullable DiscountService discountService) {
// discountService may be null
}
}Explanation
Since Spring 5.0,
@Nullablecan be applied to parameters to indicate the bean is optional.
9. Lazy Injection
@Component
class OrderService {
@Autowired
@Lazy
private PaymentService paymentService;
}Explanation
Bean creation is deferred until
paymentServiceis first accessed.Useful for breaking circular dependencies or speeding up startup.
10. Collection Injection
@Component
class OrderService {
@Autowired
private List<PaymentService> paymentServices;
@Autowired
private Map<String, PaymentService> paymentServiceMap;
}Explanation
Injects all beans of a given type into a
ListorMap.Listis ordered by@Orderor bean definition order.Mapkeys are bean names.
11. Self-Defined Bean Selection with Collection Filtering
@Component
class FastPaymentService implements PaymentService { }
@Component
class SlowPaymentService implements PaymentService { }
@Component
class OrderService {
@Autowired
@Qualifier("fastPaymentService")
private PaymentService paymentService;
@Autowired
private List<PaymentService> allPaymentServices;
}Explanation
Injects one specific bean via qualifier, but also injects all available beans into a collection.
12. Injection in @Configuration Class
@Configuration Class@Configuration
class AppConfig {
private final PaymentService paymentService;
@Autowired
public AppConfig(PaymentService paymentService) {
this.paymentService = paymentService;
}
@Bean
public OrderService orderService() {
return new OrderService(paymentService);
}
}Explanation
Constructor injection in configuration classes ensures dependencies are ready when defining beans.
13. Circular Dependency Example (Setter-Based Fix)
@Component
class ServiceA {
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Component
class ServiceB {
private final ServiceA serviceA;
@Autowired
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}Explanation
Field or setter injection can resolve circular dependencies between beans of singleton scope.
Constructor-based circular dependencies cause errors.
Last updated