Why Field Injection Is Not Recommended in Spring and Preferred Alternatives
This article explains why Spring’s field injection is discouraged, outlines constructor‑based, setter‑based, and field‑based injection methods with code examples, discusses the drawbacks of field injection such as hidden dependencies and poor testability, and recommends using constructor injection for required beans and setter injection for optional ones.
Introduction: While coding in IntelliJ IDEA, a warning appears for field injection such as:
@Autowire
private JdbcTemplate jdbcTemplate;The warning states that field injection is not recommended; the Spring team advises always using constructor‑based dependency injection and assertions for mandatory dependencies.
Spring defines three injection types: constructor‑based, setter‑based, and field‑based.
Constructor‑based injection example:
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Autowire
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
}Setter‑based injection example:
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Autowire
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}Field‑based injection example:
public class UserServiceImpl implements UserService {
@Autowire
private UserDao userDao;
}Although field injection is concise and widely used, it has several drawbacks:
It cannot be used with final fields because the value must be set before the constructor finishes.
It hides the single‑responsibility principle; a class with many injected fields may indicate that it does too much.
It tightly couples the class to Spring’s IoC container, making the class harder to use outside the container.
Dependencies become private fields, obscuring what the class needs and preventing early validation of null values.
Errors due to missing dependencies surface only at runtime when the bean is first used.
Example of a constructor with many parameters that may violate the single‑responsibility principle:
public class VerifyServiceImpl implements VerifyService {
private AccountService accountService;
private UserService userService;
private IDService idService;
private RoleService roleService;
private PermissionService permissionService;
private EnterpriseService enterpriseService;
private EmployeeService employService;
private TaskService taskService;
private RedisService redisService;
private MQService mqService;
public VerifyServiceImpl(AccountService accountService, UserService userService, IDService idService,
RoleService roleService, PermissionService permissionService,
EnterpriseService enterpriseService, EmployeeService employService,
TaskService taskService, RedisService redisService, MQService mqService) {
this.accountService = accountService;
this.userService = userService;
this.idService = idService;
this.roleService = roleService;
this.permissionService = permissionService;
this.enterpriseService = enterpriseService;
this.employService = employService;
this.taskService = taskService;
this.redisService = redisService;
this.mqService = mqService;
}
}Conclusion: Avoid field injection; prefer constructor injection for mandatory dependencies to make them immutable and non‑null, and use setter injection for optional dependencies.
Postscript: This content is translated from the article “field‑injection‑is‑not‑recommended” with added personal interpretation.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
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.