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 + "!";
}
}@Servicetells 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/AliceOutput:
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