本文目的
1、了解@Autowired的作用
2、从源码探讨是如何工作的
3、如何bebug,跟踪整个过程
4、Spring是如何找到bean哪些属性被@Autowired修饰的
5、找到需要注入的属性,那属性值是又如何找到的
准备
spring framework使用5.2.19版本
idea 2021.3.3
jdk8
greadle 5.6.4
说明
首先从@Autowired的注释下手
Marks a constructor, field, setter method, or config method as to be autowired by
* Spring's dependency injection facilities.从源码注释得知,@Autowired可以作用于,setter方法、属性、构造器,配置方法【@Configuration的类中的@bean修饰的方法】。
因为比较复杂所以,下面只按属性注入的过程进行源码分析,其他注入过程,其他篇幅再叙说
@Autowired的作用
通过上面的注释说明就已经知道了,它的作用就是依赖注入,可以作用于setter方法、属性、构造器,配置方法,而且上篇文章Spring5.x之IOC也提到过修饰构造器相当于指定哪个构造器实例化。
在这里就得知有两个作用分别是,1、依赖注入;2、参构造器时指定用哪个构造器实例化
目前只得知这两大作用。
源码分析
在得知@Autowired的作用后,那它又是如何工作的呢?
测试代码
package com.csh.spring.dimodule.autowiredAnno;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AutowiredAnnoTest {
@Test
public void testByNameOrTypeAndConstruct() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.csh.spring.dimodule.autowiredAnno");
context.refresh();
Object a = context.getBean("a");
System.out.println(a);
}
}
package com.csh.spring.dimodule.autowiredAnno;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class A {
@Autowired
private B b;
}
package com.csh.spring.dimodule.autowiredAnno;
import org.springframework.stereotype.Component;
@Component
public class B {
}
如何debug
找到AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement
#inject打个断点,debug运行测试方法,再看调用栈,这样就能看到整个调用过程
Spring是如何找到哪些属性是需要注入的
通过上面的调用栈和跟踪代码能知道【源码很复杂,除了调用栈方法更细致的内容可以暂时跳过,等非常熟悉后再研究】,@Autowired注解的注入过程是在实例化目标类【这里是A类,只分析属性的,方法和构造差不多,只是封装类不一样】时扫描其中哪些属性被@Autowired修饰,封装成InjectedElement【实际封装类是AutowiredAnnotationBeanPostProcessor中的静态类AutowiredFieldElement,它继承了InjectedElement】,用于存放找到的属性放在一个set集合中,然后根据这个set集合到容器中一一将其值找到,最后注入。
需要注入的属性找到了那它的依赖值是如何找到
从流程图中可以看到它是如何从容器中找到依赖值的
DefaultListableBeanFactory#doResolveDependency
在该方法中调用了
DefaultListableBeanFactory#resolveMultipleBeans
来判断属性需要注入的是多值的从容器中【暂时认为全部都是从容器找到的】找到并直接返回,如果返回null则继续调用
DefaultListableBeanFactory#findAutowireCandidates
找到所匹配的注入类型,封装为map,beanName-》class这里之所以是返回class而不是实例可能是因为可能有多个实例后面通过name又没匹配上 //从而浪费了实例化,因为实例化生命周期非常复杂,所以等到后面name匹配成功,再根据class去实例化 通过类型找到多个class,1、是否标记了主要如@Primary,2、是否有排序,3、最后一个策略,注入值已存在或者名称匹配,最终得到一个符合的实例/目标class最后能正常拿到值如果还是class则实例化再返回如果不是直接返回该对象