Spring Exploration 丨 @Resource @Resource, @Autowired @Autowired?

When it comes to Spring dependency injection, the first thing you think of should be @Resource and @Autowired. Many articles only explain the functional differences. Why Spring supports two such similar annotations is not mentioned. It belongs to knowing it but not knowing it. So yes. I don’t know if you have thought about it when using these two annotations. @Resource supports both name and type. Why do you need @Autowired? Is Spring officially doing nothing?

Is there really nothing to do? After reading this article you will learn:

  1. @Resource and @Autowired sources
  2. Why does Spring officially support these two annotations with such similar functions?
  3. Why does Idea show a yellow warning when the @Autowired attribute is injected?
  4. Recommended usage of @Resource and @Autowired

source

Since we want to find out, we must first understand their life experience.

@Resource was released with JSR 250 on May 11, 2006. The official explanation is:

Resource annotations mark the resources required by the application. This annotation can be applied to an application component class, or to a field or method of a component class. When the annotation is applied to a field or method, the container will inject an instance of the requested resource into the application component when the component is initialized. If the annotation is applied to a component class, the annotation declares resources that the application will look for at runtime.

It can be seen that it is similar to a definition, but it is freely implemented by other components or frameworks.

@Autowired was released with Spring 2.5 on November 19, 2007, and @Resource was officially supported at the same time. The official explanation from @Autowired is:

Marks a constructor, field, setter, or configuration method to be autowired by Spring's dependency injection tools.

As you can see, @Autowired is the son of Spring, and @Resource is an implementation defined by Spring, and their functions are so similar. So why support @Resource, but also build @Autowired yourself?

I specifically checked the official documentation of Spring 2.5. There is a paragraph in the document that says:

However, Spring 2.5 dramatically changes the landscape. As described above, the autowiring choices have now been extended with support for the JSR-250  @Resource annotation to enable autowiring of named resources on a per-method or per-field basis. However, the  @Resource annotation alone does have some limitations. Spring 2.5 therefore introduces an  @Autowired annotation to further increase the level of control.

It roughly means that Spring 2.5 supports automatic assembly of annotations, and now supports JSR-250 @Resource automatic assembly of named resources based on each method or field, but only @Resource is not enough, we also launched @Autowired with a larger "granularity" to cover more scenarios.

Uh-huh, then the official "granularity" is the key, so what does the "granularity" refer to"?

Both gave birth to "@Resource", He gave birth to "@Autowired"

To find out what the granularity is, let's start with the functions of the two annotations

@Autowired

  • type injection

@Resource

  • The name injection is given priority, and the name cannot be found to find the type

Regarding the "granularity" of the function, @Resource already includes @Autowired, and the "granularity" is larger. Isn't this the case in Spring 2.5? I went through the Spring2.5 document again, and it clearly stated:

When using  @Resource without an explicitly provided name, if no Spring-managed object is found for the default name, the injection mechanism will fallback to a type-match.

Isn't it the same as now, I'm messed up now. So what exactly does "granularity" refer to? After wandering through many forums, a passage from stackoverflow caught my attention:

Both  @Autowired and  @Resource work equally well. But there is a conceptual difference or a difference in the meaning.
@Resource means get me  a known resource by name. The name is extracted from the name of the annotated setter or field, or it is taken from the name-Parameter.
@Inject or  @Autowired try to wire in  a suitable other component by type.
So, basically these are two quite distinct concepts. Unfortunately the Spring-Implementation of  @Resource has a built-in fallback, which kicks in when resolution by-name fails. In this case, it falls back to the  @Autowired-kind resolution by-type. While this fallback is convenient, IMHO it causes a lot of confusion, because people are.

The general meaning is: Although Spring implements two similar functions, there are conceptual differences or differences in meaning:

  • @Resource This gives me a definitely known resource by name.
  • @Autowired tries to wire other components that are suitable by type.

But @Resource kicks in when resolution by name fails. In this case, it resolves by type, causing conceptual confusion as developers, unaware of the conceptual difference, tend to use @Resource type-based autowiring instead.

It turns out that the "granularity" officially mentioned by Spring refers to the "resource range". @Resource is looking for certain known resources, which is equivalent to giving you a coordinate, and you go directly to it. @Autowired is trying to search for suitable resources in an area.

So the answer to the above question is basically clear.

Why does Spring support two annotations with similar functions?

  • Their concepts are different, @Resource tends to find known resources, while Autowired tends to try to search for resources by type.
  • To facilitate the migration of other frameworks, @Resource is a specification, as long as other frameworks conform to the JSR-250 specification, Spring is compatible.

Since @Resource is more inclined to find known resources, why does it also have the function of injecting by type?

  • Personal guess: It may be for compatibility with switching from Spring to other frameworks. Even if developers only use Resource, they still maintain Spring's powerful dependency injection function.

Spring's distinction

Seeing this, I believe everyone has their own opinions on whether to use @Resource or @Autowired. There is a small detail in daily code writing. I don’t know if you have noticed. When using @Autowired on the property, Idea will expose a yellow warning and recommend us to use constructor injection, but Resource will not. Why is this? Woolen cloth? The warning is as follows:

Why does Idea show a yellow warning when @Autowired is on the property, and recommends us to use constructor injection?

In fact, the answer has been given in the Spring document, mainly in the following points:

1. Attributes that cannot be declared as constants

Attribute-based dependency injection does not apply to fields declared as final, because this field must be instantiated when the class is instantiated. The only way to declare immutable dependencies is to use constructor-based dependency injection.

2. It is easy to overlook the single principle of a class.

A class should only be responsible for a single part of a software application's functionality, and all of its services should be tightly coupled with that responsibility. If you use dependency injection of properties, it is easy to have many dependencies in your class and everything will look normal. But if you use constructor-based dependency injection instead, as more dependencies are added to your class, the constructor will grow larger and the code will start to "smell" from the start, sending a clear signal that something is wrong. question. A constructor with more than ten parameters is a clear indication that the class has so many dependencies that you have to pay attention to a single problem with the class. Therefore, although attribute injection does not directly break the single principle, it can help you ignore the single principle.

3. Circular dependency problem

Class A needs instances of class B through constructor injection, and class B needs instances of class A through constructor injection. If you configure beans for classes A and B to inject into each other, using the constructor will find out very quickly.

4. Dependency injection strongly depends on the Spring container

If you want to use this class outside the container, for example for unit testing, you have to use the Spring container to instantiate it, because there is no other possible way (except reflection) to set up automatic assembly field.

Why doesn't @Resource have it?

In the official documentation, I didn't find the answer. I checked some information and said: @Autowired is provided by Spring. Once you switch to other IoC frameworks, it cannot support injection. And @Resource is provided by JSR-250, which is The Java standard, the IoC container we use should be compatible with it, so even if the container is changed, it will work fine.

Recommended usage of @Autowired and @Resource

1. Which scene is suitable for which

Just remember one sentence, @Resource tends to be a deterministic single resource , and @Autowired is a type to match all resources that match this type .

Such as collection injection, @Resource is also possible, but it is recommended to use @Autowired. As can be seen from the small green mark on the left side of the idea, it is not recommended to use @Resource to inject collection resources. In essence, collection injection is not single, but also uncertain.

2. @Autowired recommended usage

Method 1: Use constructor injection (recommended)

native version:

Elegant version: @RequiredArgsConstructor+private final using lombok

Method 2: set injection

native version:

Elegant version: @Setter using lombok

Author: Wang Junwu (at Xuan)

Original link

This article is the original content of Alibaba Cloud and may not be reproduced without permission.

Guess you like

Origin blog.csdn.net/weixin_43970890/article/details/130011272