In Spring, the @Autowired
annotation is one of the most powerful and widely used features for dependency injection. It allows Spring to resolve and inject collaborating beans into your application components automatically, without needing to instantiate them manually.
What is @Autowired
?
@Autowired
is an annotation provided by Spring that allows automatic injection of beans by type.
- Defined in:
org.springframework.beans.factory.annotation.Autowired
- Works in:
- Constructors
- Setters
- Fields
Types of Dependency Injection with @Autowired
Type | Description |
---|---|
Field | Directly inject into a field (common but less testable) |
Setter | Inject via setter method |
Constructor | Preferred for immutability and testability |
Example Project: Using @Autowired
in All 3 Ways
Let’s build a simple Spring Boot application with a GreetingService
that will be injected into a GreetingController
.
1. Create Spring Boot Project
Use Spring Initializr or create manually with the following dependencies:
- Spring Boot Starter Web
2. Maven pom.xml
(simplified)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Step-by-Step Code Implementation
GreetingService.java
package com.example.demo.service;
import org.springframework.stereotype.Service;
@Service
public class GreetingService {
public String greet(String name) {
return "Hello, " + name + "!";
}
}
@Service
tells Spring to manage this class as a bean.
GreetingController.java
(3 Injection Styles)
package com.example.demo.controller;
import com.example.demo.service.GreetingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/greet")
public class GreetingController {
private GreetingService greetingService;
// ✅ Constructor Injection (Preferred)
@Autowired
public GreetingController(GreetingService greetingService) {
this.greetingService = greetingService;
}
// ✅ Field Injection (Less testable)
// @Autowired
// private GreetingService greetingService;
// ✅ Setter Injection (Optional)
// @Autowired
// public void setGreetingService(GreetingService greetingService) {
// this.greetingService = greetingService;
// }
@GetMapping("/{name}")
public String greet(@PathVariable String name) {
return greetingService.greet(name);
}
}
Test the API
Start the application and hit:
http://localhost:8080/greet/Alice
Output:
Hello, Alice!
Optional: Handle Multiple Beans with @Qualifier
If you have multiple beans of the same type, use @Qualifier
:
@Service("friendlyService")
public class FriendlyGreetingService implements GreetingService {
public String greet(String name) {
return "Hey buddy, " + name + "!";
}
}
@Autowired
@Qualifier("friendlyService")
private GreetingService greetingService;
Notes and Best Practices
Practice | Recommendation |
---|---|
Prefer constructor injection | Better for immutability, testability, and clarity |
Avoid field injection | Difficult to unit test without reflection |
Use @Qualifier when needed | If multiple beans implement same interface |
Required=true by default | Add @Autowired(required=false) to make optional |
Common Errors
Error | Cause | Solution |
---|---|---|
No qualifying bean | Bean not scanned or defined | Annotate with @Component , @Service , etc. |
NullPointerException | Field not injected | Use correct injection method or check config |
Summary
Feature | Support |
---|---|
Field Injection | yes |
Setter Injection | yes |
Constructor Injection | yes (Recommended) |
Optional Beans | yes via @Autowired(required = false) |
Multiple Beans | yes via @Qualifier |
Final Directory Structure
src/
└── main/
└── java/
└── com/example/demo/
├── DemoApplication.java
├── controller/
│ └── GreetingController.java
└── service/
└── GreetingService.java