1. Analysis from the usage level
First, we create an interface
UserService and two implementation classes
We can then perform dependency injection where we need to use
In the above code, the
@Resource annotation injects the
UserService object directly into the
userService property, while the
@Autowired annotation needs to be combined with the
@Qualifier annotation to specify the specific bean name and the
required attribute to set whether or not it must be injected into the object. Note that the
@Qualifier annotation can also be omitted from the
@Autowired annotation, which will match the corresponding bean by type.
2. Analysis from the conceptual level
The implementation principle of dependency injection in Spring Framework is based on the Java reflection mechanism and JavaBean specification.
Instantiate objects through the reflection mechanism
The Spring framework instantiates the bean object to be injected through the reflection mechanism and stores it in a Map, where Key is the bean name and Value is the bean instance object.
bean property injection via the JavaBean specification
Next, Spring will find the property to be injected based on the JavaBean specification (i.e. the property name and the setter method of the property) and call the corresponding setter method to inject the property through the reflection mechanism.
Search strategies for dependency injection
During dependency injection, the Spring Framework typically uses two search strategies:
Search by type: When the type of the property to be injected matches the type of multiple beans in the container, a different search strategy is chosen depending on the annotation. For example, when using the @Autowired annotation, the default is to find the corresponding bean by type matching.
Search by name: When the type of the property to be injected is not unique, or the name of the bean to be injected does not match the name of the property, you can use the @Qualifier annotation to specify the name of the bean to be injected.
using various annotations for dependency injection
The Spring framework provides a variety of annotations for dependency injection, including:
@Autowired: injection by type;
@Resource: injection by name;
@Value: injection of properties of simple types or string types;
@Inject: an annotation defined by the JSR-330 standard, similar in function to
The Spring Framework’s implementation of dependency injection is based on the Java reflection mechanism and the JavaBean specification, and is implemented in different ways through various annotations.
@Autowired are Spring dependency injection annotations, but they differ as follows:
@Resourceis an annotation defined by the Java EE specification, whereas
@Autowiredis an annotation provided by Spring.
Attributes are different: The
@Resourceannotation does not have a required attribute, but a name attribute that indicates the name of the bean to be injected, while the
@Autowiredannotation has a required and a name attribute, where required indicates whether the object must be injected and defaults to true, and name indicates the name of the bean to be injected.
Different lookup method:
@Resourceannotation by default is based on byName, if not found then byType, while
@Autowiredby default is based on byType.
Compatibility differences: The
@Resourceannotation can be used with the @Inject annotation in JSR-330; the
@Autowiredannotation can only be used with Spring components.
Different application scenarios: The
@Resourceannotation is mainly used in Java EE environments, while the
@Autowiredannotation is one of the most widely used dependency injection annotations in the Spring Framework and can be applied to different application scenarios.
The advantages and disadvantages of the
@Autowired annotations are described separately below:
- simple to use and very easy to use in classes.
- Can be used in conjunction with the @Inject annotation.
- Supports specifying bean names for more precise dependency injection.
- the Spring framework for
@Resourceannotation support is not as rich as
- only support byName and byType two injection methods, more limited than
- support for complex dependency injection configuration , you can dependency injection in a variety of ways.
- the Spring framework for
@Autowiredannotation support is very rich, is one of the most widely used annotations in Spring.
- you can specify whether the property must be injected, or you can specify the bean name for injection.
- In addition to using it in classes, you can also use the
@Autowiredannotation in constructors, Setter methods and any method annotated with
- more cumbersome to configure, need to specify required and name attributes etc.
- need to follow Spring’s automatic scanning mechanism, only classes marked with annotations such as
@Repositorywill be managed by the Spring container.
The principle of dependency injection can be summarised in three simple steps:
- At application startup, the Spring container is responsible for creating and managing all bean instance objects.
- when a bean needs to be used, the Spring container injects the bean into the class or object that needs to be used through the reflection mechanism.
- During the bean injection process, the Spring container will use different dependency injection methods depending on the annotation (e.g.
@Autowired) to complete the dependency injection process.
@Autowired are dependency injection annotations provided by Spring, each with its own advantages and disadvantages. In practice, you can choose the right annotation to use depending on the specific application scenario.
2. Analysis from the code level
At the Spring Framework source level, the fully qualified paths for the
@Autowired annotations are
org.springframework.beans.factory.annotation.Autowired. Let’s take a look at their implementation.
Implementation principles of
- if the name attribute of the @Resource annotation is not empty, the Spring container looks for the bean instance object to be injected based on the value of the attribute; if the name attribute is empty, the default is to use the field name as the bean name to look for it.
- The Spring container will first look for the bean instance based on the byName injection method, and if it does not find the corresponding bean instance, it will look for it based on the byType method.
- If the corresponding bean instance is found, the bean instance is injected into the class or object that needs to use it using the reflection mechanism.
- If the corresponding bean instance is not found, a
How the @Autowired annotation is implemented:
- The Spring container will process the AutowiredAnnotationBeanPostProcessor class and the derived classes of the AutowiredAnnotationBeanPostProcessor class according to their derivatives, injecting all the properties marked with the @Autowired annotation into the class that needs to be used or object to be used.
- For the AuthorizedAnnotationBeanPostProcessor, which implements the BeanPostProcessor interface, the @Autowired annotation is intercepted during the instantiation and initialization of the bean.
- When the Spring container encounters an @Autowired annotation, it will automatically call the postProcessPropertyValues method of the AutowiredAnnotationBeanPostProcessor class, which will perform different dependency injection processes depending on the value of the annotated property.
- When handling @Autowired annotations, the Spring container by default uses the byType method to look up the bean and if there are multiple beans of matching types, they are matched by class name; if it is still not sure which bean to inject, a NoSuchBeanDefinitionException is thrown.
@Resource annotation and the @
Autowired annotation are implemented in the Spring Framework source code through the reflection mechanism and the
BeanPostProcessor interface for dependency injection. In practice, we can study the corresponding source implementations to get a deeper understanding of how they work, so that we can use these dependency injection annotations better.