@autowired dependency injection is not recommended

Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

At the same time, I participated in the Digitalstar project to win the creative gift package and challenge the creative incentive money

The introduction

When using IDEA, all the members of the same group like to inject @Autowired with a piece of warning code, which is very uncomfortable to look at. @Autowired is the son of Spring, why there is a warning in IDEA: Field injection is not recommended

Before we get to the bottom of this, let’s look at dependency injection in a few ways

Three ways to inject Spring

Property (filed) Injection

This type of injection is dependency injection using annotations on bean variables. It is essentially injected directly into the field by reflection. This is one of the most familiar approaches I see in development.

@Autowired 
UserDao userDao;
Copy the code

Constructor injection

Constructor based injection is done by placing all required dependencies in parameters with annotated constructors and initializing the corresponding variables in the constructor. Such as:

final
UserDao userDao;

@Autowired
public UserServiceImpl(UserDao userDao) {
    this.userDao = userDao;
}
Copy the code

Set method injection

Dependency injection is done by using the setXXX() method of the corresponding variable and using annotations on the method. Such as:

private UserDao userDao;

@Autowired
public void setUserDao (UserDao userDao) {
    this.userDao = userDao;
}
Copy the code

Possible problems with property injection

Problem a

Field-based injection can introduce some implicit problems. Let’s take an example:

@Autowired
private User user;

private String company;

public UserDaoImpl(a){
    this.company = user.getCompany();
}
Copy the code

No errors are reported during compilation, but NullPointerException is reported after execution

Instantiation ofbean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [...] : Constructor threw exception; nested exception is java.lang.NullPointerExceptionCopy the code

Java initializes a class in the order of static variables or static statement blocks -> instance variables or initialization statement blocks -> constructor -> @autoWired. So when the constructor of this class is executed, the User object has not yet been injected and its value is still null.

Question 2

Cannot effectively specify dependencies. Many of you have encountered a bug where the dependency injection object is null. When you start the dependency container, you encounter this bug because the configured dependency injection object is missing an annotation or something. This approach is too dependent on the injection container, and without starting the entire dependency container, the class will not work and will not provide the dependencies the class needs at reflection time.

Question 3

One of the core ideas of dependency injection is that container-managed classes should not depend on container-managed dependencies. To put it in plain English, if the class uses a dependency injection class, then the class must function without these dependencies. However, using variable injection does not guarantee this.

Spring advice

Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies.

Translation:

Mandatory dependencies are constructors, and mutable dependencies are setters

Use @resource instead of @autowired

@resource has two attributes name and type. In Spring, the name attribute is defined as the bean name, and type is the type of the bean. If the attribute is annotated with @Resource then its injection flow is

  • If both name and Type are specified, a unique matching bean is found from the Spring context and assembled, failing which an exception is thrown.
  • If name is specified, the bean with a matching name is searched from the context for assembly, and an exception is thrown if no bean is found.
  • If type is specified, an exception will be thrown if a unique bean whose type matches is found in the context and assembled.
  • If neither name nor type is specified, byName is used for assembly by default. If no match is found, byType is used for assembly.

@autoWired will only inject based on type and will not match name. When it comes to type not being able to identify injected objects, you need to rely on the @qualifier or @primary annotations in combination.

Inject using the @requiredargsconstructor constructor

This form of injection is the constructor method recommended by Spring. This method is an annotation in the Lombok package. To use this method, lombok needs to be introduced into the project, for example:

@RequiredArgsConstructor
public class UserDaoImpl{
	private final User user;
}
Copy the code