The introduction
In practice, when using IDEA development, many code users like to use @AutoWired annotation for dependency injection. In this case, IDEA will give a yellow warning, a piece of code warning, I do not allow such an unclear warning. @autowired as Spring’s own son, why is there such a warning in IDEA? So, with my neat fetish, and my curiosity, I began to study this warning.
Here’s a quick translation of what the autoprompt means:
It is not recommended to do dependency injection directly on fields. The Spring development team recommends always using constructors for dependency injection in Java beans.
Dependency injection
Spring has three approaches to dependency injection
Field based 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. Such as:
@Autowired
UserService userService;
Copy the code
Injection based on set method
Dependency injection is done by using the setXXX() method of the corresponding variable and using annotations on the method. Such as:
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
Copy the code
Note: In Spring 4.5 and later, the @autowired annotation above setXXX is optional.
Constructor based 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:
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
Copy the code
Property injection issues
As you can see, the way variables are injected is so neat. But he did have some problems. Here are some of them:
Problem a
@Autowired
private UserService userService;
private String company;
public UserServiceImpl(a) {
this.company = userService.getCompany();
}
Copy the code
No errors are reported during compilation, but NullPointerException is reported after execution
Instantiation of bean 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.
How to solve it?
The @autowired, @Inject, and @Resource annotations are used when we need to Inject properties, and these three annotations are only supported in Spring. What’s the difference between these three annotations?
@Autowired
The @autowired annotation for the Spring framework is, understandably, Spring’s own son. Here is an example code
public interface IndexService {
void sayHello(a);
}
@Service
public class IndexServiceImpl implements IndexService {
@Override
public void sayHello(a) {
System.out.println("hello, this is IndexServiceImpl"); }}@Service
public class IndexServiceImpl2 implements IndexService {
@Override
public void sayHello(a) {
System.out.println("hello, this is IndexServiceImpl2"); }}Copy the code
The test method
@SpringBootTest
public class Stest {
@Autowired
// @Qualifier("indexServiceImpl2")
IndexService indexService;
@Test
void gooo(a) { Assertions.assertNotNull(indexService); indexService.sayHello(); }}Copy the code
Here’s the process for matching beans:
-
Find matches in the context by type, find beans of Type IndexService.
-
If there are multiple beans, they are matched by name
-
If there is an @Qualifier annotation, the name specified by @Qualifier is matched to find the bean whose name is indexServiceImpl2.
-
If not, match by variable name. Find the bean with name indexService.
-
-
If no match is found, an error is reported. @autowired (Required =false), if required is set to false (the default is true), no exception will be thrown if the injection fails.
@Inject
Under the environment of Spring, @ Inject and @autowired is the same, the dependency injection because they are using AutowiredAnnotationBeanPostProcessor this post processor to process.
The difference between the two is that @Inject is in the Java EE package and needs to be introduced separately in the SE environment. Another difference is that @AutoWired can set Required =false while @Inject does not. Some say @Inject is Spring’s godson.
@Resource
@resource is an annotation of the JSR-250 definition. Spring in CommonAnnotationBeanPostProcessor implements the handling of JSR – 250 annotations, including @ the Resource.
This @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, its injection flow looks like this:
-
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.
So we can use @Resource instead of @autowired, or we can use @requiredargsConstructor, which Spring recommends as an annotation in the Lombok package. You need to introduce Lombok into your project, for example:
@RequiredArgsConstructor
public class UserDaoImpl {
private final User user;
}
Copy the code