0%

@Autowired 注解实现原理(Spring的自动装配)

1、问题

  • @Autowired 注解是如何实现自动装配的?
  • 当为类型为 A 的 Bean 装配类型为 B 的属性时,如果此时 Spring 容器中存在多个类型为 B 的 bean ,此时 Spring 是如何处理的?
  • 自动装配的模型是什么?有哪几种?和 Autowired 注解有什么关联?

2、示例

  1. pom依赖
  2. 配置类 AppConfig,在配置类中指定扫描哪些包下的文件
  3. 定义两个 service 接口以及实现类,然后在 ClassAServiceImpl 中为其注入 ClassBService 的实现类
  4. 启动类 TestApplication ,在启动类中通过调用 getBean() 方法获取到 ClassAService 类,然后调用 find() 方法,在 find() 方法中会打印注入的 ClassBrService 对象
  5. 运行 main() 方法,最终会在 query() 方法中打印出 ClassBService 对象。
1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
1
2
3
4
5
6
7
8
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
// 指定扫描哪些包下的文件
@ComponentScan("com.yangl.test")
public class AppConfig {
}
1
2
3
public interface ClassAService {
public void find();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import com.yangl.test.service.ClassAService;
import com.yangl.test.service.ClassBService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ClassAServiceImpl implements ClassAService {

// ClassAServiceImpl 注入 ClassBService
@Autowired
private ClassBService classBService;

public void find() {
System.out.println(classBService);
}
}
1
2
public interface ClassBService {
}
1
2
3
4
5
6
import com.yangl.test.service.ClassBService;
import org.springframework.stereotype.Service;

@Service
public class ClassBServiceImpl implements ClassBService {
}
1
2
3
4
5
6
7
8
9
10
11
12
import com.yangl.test.config.AppConfig;
import com.yangl.test.service.ClassAService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
ClassAService classAService = applicationContext.getBean(ClassAService.class);
classAService.find();
}

}

输出结果

1
com.yangl.test.service.impl.ClassBServiceImpl@453da22c

3、原理

3.1、入口,源码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/**
* Marks a constructor, field, setter method, or config method as to be autowired by
* Spring's dependency injection facilities. This is an alternative to the JSR-330
* {@link javax.inject.Inject} annotation, adding required-vs-optional semantics.
*
* <h3>Autowired Constructors</h3>
* <p>Only one constructor of any given bean class may declare this annotation with the
* {@link #required} attribute set to {@code true}, indicating <i>the</i> constructor
* to autowire when used as a Spring bean. Furthermore, if the {@code required}
* attribute is set to {@code true}, only a single constructor may be annotated
* with {@code @Autowired}. If multiple <i>non-required</i> constructors declare the
* annotation, they will be considered as candidates for autowiring. The constructor
* with the greatest number of dependencies that can be satisfied by matching beans
* in the Spring container will be chosen. If none of the candidates can be satisfied,
* then a primary/default constructor (if present) will be used. Similarly, if a
* class declares multiple constructors but none of them is annotated with
* {@code @Autowired}, then a primary/default constructor (if present) will be used.
* If a class only declares a single constructor to begin with, it will always be used,
* even if not annotated. An annotated constructor does not have to be public.
*
* <h3>Autowired Fields</h3>
* <p>Fields are injected right after construction of a bean, before any config methods
* are invoked. Such a config field does not have to be public.
*
* <h3>Autowired Methods</h3>
* <p>Config methods may have an arbitrary name and any number of arguments; each of
* those arguments will be autowired with a matching bean in the Spring container.
* Bean property setter methods are effectively just a special case of such a general
* config method. Such config methods do not have to be public.
*
* <h3>Autowired Parameters</h3>
* <p>Although {@code @Autowired} can technically be declared on individual method
* or constructor parameters since Spring Framework 5.0, most parts of the
* framework ignore such declarations. The only part of the core Spring Framework
* that actively supports autowired parameters is the JUnit Jupiter support in
* the {@code spring-test} module (see the
* <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testcontext-junit-jupiter-di">TestContext framework</a>
* reference documentation for details).
*
* <h3>Multiple Arguments and 'required' Semantics</h3>
* <p>In the case of a multi-arg constructor or method, the {@link #required} attribute
* is applicable to all arguments. Individual parameters may be declared as Java-8 style
* {@link java.util.Optional} or, as of Spring Framework 5.0, also as {@code @Nullable}
* or a not-null parameter type in Kotlin, overriding the base 'required' semantics.
*
* <h3>Autowiring Arrays, Collections, and Maps</h3>
* <p>In case of an array, {@link java.util.Collection}, or {@link java.util.Map}
* dependency type, the container autowires all beans matching the declared value
* type. For such purposes, the map keys must be declared as type {@code String}
* which will be resolved to the corresponding bean names. Such a container-provided
* collection will be ordered, taking into account
* {@link org.springframework.core.Ordered Ordered} and
* {@link org.springframework.core.annotation.Order @Order} values of the target
* components, otherwise following their registration order in the container.
* Alternatively, a single matching target bean may also be a generally typed
* {@code Collection} or {@code Map} itself, getting injected as such.
*
* <h3>Not supported in {@code BeanPostProcessor} or {@code BeanFactoryPostProcessor}</h3>
* <p>Note that actual injection is performed through a
* {@link org.springframework.beans.factory.config.BeanPostProcessor
* BeanPostProcessor} which in turn means that you <em>cannot</em>
* use {@code @Autowired} to inject references into
* {@link org.springframework.beans.factory.config.BeanPostProcessor
* BeanPostProcessor} or
* {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor}
* types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
* class (which, by default, checks for the presence of this annotation).
*
* @author Juergen Hoeller
* @author Mark Fisher
* @author Sam Brannen
* @since 2.5
* @see AutowiredAnnotationBeanPostProcessor
* @see Qualifier
* @see Value
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
/**
* 声明是否需要带注释的依赖项,默认 true
*/
boolean required() default true;

}

3.1.1、AutowiredAnnotationBeanPostProcessor

由 Autowired 注释可以看到

Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor} class (which, by default, checks for the presence of this annotation)

请咨询{@link AutowiredAnnotationBeanPostProcessor}类的javadoc(默认情况下,该类检查此注释的存在)。

AutowiredAnnotationBeanPostProcessor 继承关系如下图:

1611021808079

可见它间接

  • 实现 InstantiationAwareBeanPostProcessor ,就具备了实例化前后(而不是初始化前后)管理对象的能力,
  • 实现了 BeanPostProcessor ,具有初始化前后管理对象的能力,
  • 实现 BeanFactoryAware ,具备随时拿到 BeanFactory 的能力,

也就是说这个 AutowiredAnnotationBeanPostProcessor 具备一切后置处理器的能力。

3.2、源码分析

4、总结

在容器启动,为对象赋值的时候,遇到@Autowired注解,会用后置处理器机制,来创建属性的实例,然后再利用反射机制,将实例化好的属性,赋值给对象上,这就是Autowired的原理。

参考:

https://juejin.cn/post/6844903957135884295

https://mp.weixin.qq.com/s/q6zs7xRjpcB4YxLw6w477w

https://juejin.cn/post/6844904032784515086


----------- 本文结束啦感谢您阅读 -----------