1. Analysis from the usage level
First, we create an interface UserService
and two implementation classes UserServiceImpl1
and UserServiceImpl2
.
|
|
We can then perform dependency injection where we need to use UserService
.
Use the @Resource
annotation.
Use the @Autowired
annotation.
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@Autowired
.
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.
Both @Resource
and @Autowired
are Spring dependency injection annotations, but they differ as follows:
-
Different sources:
@Resource
is an annotation defined by the Java EE specification, whereas@Autowired
is an annotation provided by Spring. -
Attributes are different: The
@Resource
annotation does not have a required attribute, but a name attribute that indicates the name of the bean to be injected, while the@Autowired
annotation 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:
@Resource
annotation by default is based on byName, if not found then byType, while@Autowired
by default is based on byType. -
Compatibility differences: The
@Resource
annotation can be used with the @Inject annotation in JSR-330; the@Autowired
annotation can only be used with Spring components. -
Different application scenarios: The
@Resource
annotation is mainly used in Java EE environments, while the@Autowired
annotation 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 @Resource
and @Autowired
annotations are described separately below:
Advantages of @Resource
:
- 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.
@Resource
disadvantages:
- the Spring framework for
@Resource
annotation support is not as rich as@Autowired
. - only support byName and byType two injection methods, more limited than
@Autowired
support.
@Autowired
Advantages:
- support for complex dependency injection configuration , you can dependency injection in a variety of ways.
- the Spring framework for
@Autowired
annotation 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
@Autowired
annotation in constructors, Setter methods and any method annotated with@Bean
.
Disadvantages of @Autowired
:
- 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
@Component
,@Service
,@Controller
and@Repository
will 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.
@Resource
,@Autowired
) to complete the dependency injection process.
Both @Resource
and @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 @Resource
and @Autowired
annotations are javax.annotation.Resource
and org.springframework.beans.factory.annotation.Autowired
. Let’s take a look at their implementation.
Implementation principles of @Resource
annotation:
- 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
NoSuchBeanDefinitionException
is thrown.
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.
Both the @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.
Reference:
https://juejin.cn/post/7223286420794966076