Why Field Injection in Spring Is Risky and How Constructor Injection Solves It
The article explains how field injection in Spring can cause null‑pointer exceptions, break immutability, violate design principles, and hide circular dependencies, and demonstrates that using constructor injection (with optional @Lazy) provides safer, more maintainable dependency management.
1. Introduction
Dependency injection allows an object to use its dependencies without manually creating them; it is a core feature of Spring.
Spring supports three injection types: constructor injection, setter injection, and field injection (using @Autowired ). Field injection is simple but can cause problems.
2. Problems Caused by Field Injection
2.1 Null‑Safety
If a dependency is not initialized, field injection can lead to NullPointerException . Example code:
<code>@Repository
public class PersonDAO {}
@Service
public class PersonService {
// @Autowired
@Resource
private PersonDAO dao;
public String toString() {
return "PersonService [dao=" + dao + "]";
}
}
</code>When the container starts, using @Autowired without a bean causes startup errors; using @Resource also leads to NPE at runtime.
Creating the service manually also results in NPE:
<code>PersonService ps = new PersonService();
ps.xxx();
</code>Constructor injection avoids this by requiring the dependency:
<code>private final PersonDAO dao;
public PersonService(PersonDAO dao) {
this.dao = dao;
}
</code>2.2 Immutability
Field injection prevents creation of immutable classes because final fields cannot be injected; constructor injection is needed for immutable dependencies.
2.3 Design Issues
Using field injection can violate the Single Responsibility Principle by adding unnecessary dependencies, and it can hide circular dependencies.
Example of circular dependency with field injection:
<code>@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
</code>Spring may allow this circular dependency, but from Spring Boot 2.6 onward it throws BeanCurrentlyInCreationException .
Note: In plain Spring circular dependencies are allowed by default, but Spring Boot 2.6+ disallows them.
Solution: use constructor injection with @Lazy on one side.
<code>public A(@Lazy B b) {
this.b = b;
}
</code>In summary, prefer constructor injection for required dependencies and use setter injection only for optional ones.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.