introduce

Today, when I was writing the code using Idea, I saw the warning displayed in the previous project, so I checked it. Is it the following code?

@Autowire
private JdbcTemplate jdbcTemplate;
Copy the code

Warning message

Field injection is not recommended Inspection info: Spring Team recommends: “Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies”.

The Spring working group recommends:

Property field injection is not recommended. The problem we checked was :” Always use construction-based dependency injection in beans and always use assertions for mandatory dependencies.”

As shown in figure

Injection pattern

While the current documentation on the Spring Framework (5.0.3) defines only two main types of injection, there are actually three:

Constructor-based dependency injection

public class UserServiceImpl implents UserService{
    private UserDao userDao;
    
    @Autowire
    public UserServiceImpl(UserDao userDao){
        this.userDao = userDao; }}Copy the code

Setter-based dependency injection

public class UserServiceImpl implents UserService{
     private UserDao userDao;
     
     @Autowire
     public serUserDao(UserDao userDao){
         this.userDao = userDao; }}Copy the code

Field-based dependency injection

public class UserServiceImpl implents UserService{
     @Autowire
     private UserDao userDao;
}
Copy the code

Field-based dependency injection gets a yellow card in Idea, but it is also the most widely used because of its simplicity. You can even see this injection method in some of the Spring guides, although it is not recommended in the documentation.

As shown in figure Disadvantages of field-based dependency injection

Does not work with variables that have final modifications

Spring’s IOC uses the set form for property injection, but variables of final type need to be initialized during the call to the class constructor, which is something that field-based dependency injection cannot do. Can only useBased on constructorsDependency injection

We all know that there is a single responsibility philosophy in OOP design. If you use Spring IOC in a constructor-based dependency injection way, when you inject too much, the constructor parameters can be very large, similar to the following.

When you see how many arguments the constructor of this class takes, you naturally wonder: does this class violate the idea of a single responsibility? But using field-based dependency injection won’t let you know, and you’ll be immersed in @Autowire

public class VerifyServiceImpl implents 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 SystemLogDto(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; }}Copy the code

Tightly coupled to Spring’s IOC mechanism

When you use field-based dependency injection, you can omit the constructor and setter template types, but you give Spring’s IOC full control, and other classes want to reset one of your injected properties, which can’t be handled (reflection can, of course).

As a result, by coupling it again to the class injector (Spring, in this case), you lose the decoupling of the class through auto-assembly of the class fields, invalidating the class outside the Spring container.

Hiding dependencies

When you use Spring’s IOC, the injected class should use some method of public type (constructor, setter type method) to say to the outside world: WHAT dependencies do I need? But the field-based dependency injection (DI) approach is mostly private, and private seals all attributes into the class.

The injected properties cannot be checked

Dependency injection method based on field, when you start the program can’t take this class, only when it is used in the real business get, in general, the injection are null, one thousand if null to do, when the business process just came out wrong, time is a bit late, if he exposed at startup, Bugs can be fixed quickly (you can annotate them, of course).

If you want to do something on the injected object when the property is injected, you can’t do it. I have encountered examples: some configuration information ah, some people always match the wrong, and so on their own test business phase just know that the wrong, such as the initial number of threads accidentally configured to 3000, the machine is really crazy ah! In this case, a detection mechanism is needed for some Value injection.

Conclusion From the above, we can see that the field-based dependency injection approach has many disadvantages, we should avoid the use of field-based dependency injection. The recommended approach is to use constructor-based and setter-based dependency injection. For required dependencies, construction-based injection is recommended to make them immutable and prevent them from being NULL. For optional dependencies, setter-based injection is recommended