Spring注解之@Autowired
前⾔
说起Spring的@Autowired注解,想必⼤家已经熟悉的不能再熟悉了。本⽂就针对此最常⽤的注解,梳理⼀下它的功能和原理,争取从源码的⾓度将此注解讲通,如有写的不准确的地⽅,欢迎各位园友拍砖。
注:此篇博⽂基于Spring5.1.10.RELEASE,SpringBoot2.1.9.RELEASE
正⽂
⾸先看⼀下@Autowired注解的源码
1package org.springframework.beans.factory.annotation;
2
3import java.lang.annotation.Documented;
4import java.lang.annotation.ElementType;
5import java.lang.annotation.Retention;
6import java.lang.annotation.RetentionPolicy;
7import java.lang.annotation.Target;
8
9 @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
10 @Retention(RetentionPolicy.RUNTIME)
11 @Documented
12public @interface Autowired {
13
14/**
15 * Declares whether the annotated dependency is required.
16 * <p>Defaults to {@code true}.
17*/
18boolean required() default true;
19
20 }
可以看到,此注解运⾏时⽣效,且适⽤范围很⼴,从构造器,到⽅法,到参数、属性、注解,都可以加上@Autowired注解。它还有⼀个属性required,此属性⽤于控制如果不到要依赖注⼊的对象时是否报错,默认true即默认不到要注⼊的对象时会报错。下⾯我们慢慢梳理,将@Autowired的使⽤场景⼀⼀罗列出来。
⼀、普通⽤法,依赖注⼊成员变量
下⾯将要⽤的测试类贴出来,⾸先是接⼝
bokeyuan.springAutowiredDemo;
2
3public interface IndexInterface {
4 }
再就是两个⼦类
bokeyuan.springAutowiredDemo;
2
3import org.springframework.stereotype.Component;
4
5 @Component
6public class IndexService implements IndexInterface{
7
8 }
bokeyuan.springAutowiredDemo;
2
3import org.springframework.stereotype.Component;
4
5 @Component
6public class OtherIndexService implements IndexInterface{
7
8 }
核⼼类(后续的各种场景演⽰均只基于此类进⾏改动)
bokeyuan.springAutowiredDemo;
2
3import org.springframework.beans.factory.annotation.Autowired;
4import org.springframework.stereotype.Component;
5
6 @Component
7public class MyService {
8
9 @Autowired
10private IndexService indexService;
11
12 }
扫描配置类
bokeyuan.springAutowiredDemo;
2
3import t.annotation.ComponentScan;
6 @Configuration
7 @ComponentScan("bokeyuan.springAutowiredDemo")
8public class AutowiredConfig {
9 }
main⽅法类
bokeyuan.springAutowiredDemo.client;
2
bokeyuan.springAutowiredDemo.AutowiredConfig;
bokeyuan.springAutowiredDemo.MyService;
5import t.annotation.AnnotationConfigApplicationContext;
6
7public class DemoClientTest {
8public static void main(String[] args) {
9 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutowiredConfig.class);
10 System.out.Bean(MyService.class));
11
12 }
13 }
运⾏main⽅法时,如果在第10⾏打了断点,会看到MyService中的indexService属性已经依赖注⼊了值,这是我们最常使⽤@Autowired注解的场景。
⼆、依赖注⼊⽅法
MyService类如下所⽰
bokeyuan.springAutowiredDemo;
2
3import org.springframework.beans.factory.annotation.Autowired;
4import t.ApplicationContext;
5import org.springframework.stereotype.Component;
6
7import java.util.List;
8
9 @Component
10public class MyService {
11
12private IndexService indexService;
13
14 @Autowired
15public void getIndexInterf (IndexService index) {
16 indexService = index;
17 }
18
19 @Autowired
20private ApplicationContext applicationContext;
21
22 }
运⾏main⽅法后,会发现该类中的indexService完成了注⼊,这样的⽤法类似于set⽅法的功能。并且可以看到,applicationContext也注⼊了。所以往后就不要⽤ApplicationContextAware了,直接@Autowired轻快便捷的达到⽬的。
三、构造⽅法注⼊参数
MyService类如下所⽰:
bokeyuan.springAutowiredDemo;
2
3import org.springframework.beans.factory.annotation.Autowired;
4import org.springframework.stereotype.Component;
5
6import java.util.List;
7
8 @Component
9public class MyService {
10
11
12private IndexService indexService;
13
14private List<IndexInterface> indexList;
15
16 @Autowired
17public MyService (List<IndexInterface> indexList, IndexService indexService) {
18this.indexList = indexList;
19this.indexService = indexService;
20 }
21 }
运⾏后会发现成员变量indexList和indexService中已经注⼊了值。此处需要注意⼀点,如果有两个⾃定义构造⽅法,两个都没加@Autowired注解,则会报错,因为Spring不知道你要⽤哪个构造⽅法初始化;
如果只有⼀个构造⽅法加了@Autowired注解,那么就会⽤这个构造⽅法初始化;同理,如果有多个构造⽅法都加了@Autowired注解,那么还是会报错。
四、注⼊Map、List等集合
在【⼀、普通⽤法】中的MyService⾥添加⼏个成员变量,如下所⽰:
bokeyuan.springAutowiredDemo;
4import org.springframework.stereotype.Component;
5
6import java.util.List;
7import java.util.Map;
8import java.util.Set;
9
10 @Component
11public class MyService {
12
13 @Autowired
14private IndexService indexService;
15
16 @Autowired
17private List<IndexInterface> indexList;
18
19 @Autowired
20private Map<String, IndexInterface> indexMap;
21
22 @Autowired
23private Set<IndexInterface> indexSet;
24 }
再次运⾏main⽅法,在断点中可以看到从Spring中获取到的MyService对象中,已经完成了对后⾯三个集合的依赖注⼊,如下图所⽰:
可以看到,IndexInterface接⼝的两个实现类全部注⼊到了集合中,且Map⾥⾯的key默认就是两个实现类各⾃的beanName。
五、源码分析
看了上⾯的各种使⽤场景,想必⼤家会对这个最熟悉的注解有了⼀丝陌⽣的感觉,不过不要紧,下⾯咱们慢慢来脱下TA的神秘⾐服,对ta重新熟悉起来。我这⾥是以下⾯的MyService类为例⼦进⾏的源码debug分析。
bokeyuan.springAutowiredDemo;
2
3import org.springframework.beans.factory.annotation.Autowired;
4import t.ApplicationContext;
5import org.springframework.stereotype.Component;
6
7import java.util.List;
8
9 @Component
10public class MyService {
11
12
13private IndexService indexService;
14
15private List<IndexInterface> indexList;
16
17 @Autowired
18public void getIndexInterf (IndexService index) {
19 indexService = index;
20 }
21
22 @Autowired
23private ApplicationContext applicationContext;
24
26public MyService (List<IndexInterface> indexList) {
27this.indexList = indexList;
28 }
29 }
⾸先在AutowiredAnnotationBeanPostProcessor#postProcessProperties的⽅法中打上⼀个断点,然后右键断点加上条件过
滤 beanName.equals("myService"),debug运⾏main⽅法,会在断点处停住,此时我们的调⽤栈是下图这样的:
相信对Spring源码有过了解的园友对调⽤栈中的⽅法都不陌⽣,从下往上看,先经过了refresh⽅法,在finishBeanFactoryInitialization⽅法中getBean,然后⾛getObject的时候触发bean的初始化。
bean的初始化是⼀个很复杂地⽅,在AbstractAutowireCapableBeanFactory#doCreateBean⽅法中,先
创建⼀个BeanWrapper,它的内部成员变量wrappedObject中存放的就是实例化的MyService对象,只是此时未完成初始化,所以属性都是null(如下图所⽰)。再往后进⼊populateBean⽅法进⾏属性注⼊,这才逐渐逼近我们的⽬的地。
不过在进⼊populateBean之前,需要先去看⼀下前置⽅法,即BeanWrapper创建的⽅法createBeanInstance。Spring在这个⽅法中先推断出合适的构造⽅法,然后实例化bean。在推断构造⽅法的时候(AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors⽅法中调⽤了AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors⽅法进⾏的推断),有⼀个筛选标准就是会根据是否有@Autowired注解来选择⽤哪个构造器,具体详见AutowiredAnnotationBeanPostProcessor#findAutowiredAnnotation⽅法,此⽅法如下所⽰,功能就是看看当前构造器上加没加注解。
1 @Nullable
2private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
3if (ao.getAnnotations().length > 0) { // autowiring annotations have to be local
4for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {// 此集合中只有两个值,⼀个是Autowired注解,⼀个是Value注解
5 AnnotationAttributes attributes = MergedAnnotationAttributes(ao, type);
6if (attributes != null) {
7return attributes;
8 }
9 }
10 }
12 }
此处构造器的推断和属性注⼊,就是使⽤场景三【三、构造⽅法注⼊参数】中,@Autowired注解加在构造器上发挥的作⽤。
⾛完createBeanInstance⽅法得到的BeanWrapper中,可以看到属性wrappedObject中已经对indexList进⾏了依赖注⼊
进⾏到这⾥,有必要重新梳理清楚类构造器注⼊时的调⽤关系,⽰例的调⽤栈图如下所⽰:
1、在myService对象进⾏实例化调⽤构造器时,执⾏AbstractAutowireCapableBeanFactory#autowireConstructor⽅法;
2、进⼊到另⼀个类ConstructorResolver的autowireConstructor⽅法中;
2.1、调⽤同类下的resolveAutowiredArgument⽅法,该⽅法会调⽤DefaultListableBeanFactory下的resolveDependency⽅法,此⽅法会调⽤到findAutowireCandidates⽅法,在该⽅法中有如下代码
1 for (String candidate : candidateNames) {
2 if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
3 addCandidateEntry(result, candidate, descriptor, requiredType);
4 }
5 }
其中的candidateNames就是构造器中要注⼊的对象名字indexService和otherIndexService,此处通过循环调⽤addCandidateEntry来获取这两个name对应的bean;spring framework和spring的关系
2.2、在DefaultListableBeanFactory的addCandidateEntry⽅法中,调到了DependencyDescriptor#resolveCandidate⽅法,在此⽅法中调⽤的getBean⽅法获取它的成员变量bean。
DependencyDescriptor#resolveCandidate⽅法如下所⽰:
1 public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
2 throws BeansException {
3
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论