Understanding @Autowired Injection Issues and Alternative Approaches in Spring
The article explains common problems with Spring's @Autowired injection, compares it with @Resource, and presents alternative injection methods—including setter, constructor, and Lombok-based approaches—while providing code examples and best‑practice recommendations for reliable bean initialization.
Spring's dependency injection can cause initialization problems, especially when @Autowired fields are processed after subclass constructors, potentially leading to NullPointerExceptions. The article first outlines the Java class initialization order: static fields and blocks of the parent class, then those of the child, followed by instance fields, instance blocks, and constructors.
It highlights that @Autowired injection is queued after the subclass constructor, and Spring IoC does not check for null beans, so misuse may cause runtime errors. The discussion then compares @Autowired (Spring‑specific) with @Resource (JSR‑250 standard), noting that @Autowired creates a strong coupling to the Spring framework, while @Resource is more portable.
Additional concerns include excessive dependencies that violate the Single Responsibility Principle and the inability to inject immutable objects via field injection. The article suggests balancing loose coupling with practical development needs.
Alternative injection methods are presented. Setter injection using @Autowired on a setter method is shown:
@RestController
public class TestController2 {
ITestService testService;
/* Based on setter injection */
@Autowired
public void setTestService(ITestService iTestService) {
this.testService = iTestService;
}
@GetMapping("/status2")
public Result
status() {
return testService.status();
}
}Constructor injection, which avoids circular dependencies and is considered the most reliable, is demonstrated:
@RestController
public class TestController1 {
ITestService testService;
/* Based on constructor injection */
public TestController1(ITestService iTestService) {
this.testService = iTestService;
}
@GetMapping("/status1")
public Result
status() {
return testService.status();
}
}A simplified constructor approach using Lombok's @RequiredArgsConstructor is also described. After adding the Lombok dependency:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
</dependency>the class can be written as:
@RestController
@RequiredArgsConstructor
public class TestController3 {
private final ITestService testService;
@GetMapping("/status3")
public Result
status() {
return testService.status();
}
}The article concludes that constructor injection, especially when combined with Lombok, provides a concise and reliable way to manage dependencies, while setter injection remains a viable alternative when needed.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.