Spring5.x之@Autowired原理

本文目的

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的作用后,那它又是如何工作的呢?

@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集合到容器中一一将其值找到,最后注入。

需要注入的属性找到了那它的依赖值是如何找到

@Autowired寻找属性值流程图 


从流程图中可以看到它是如何从容器中找到依赖值的
DefaultListableBeanFactory#doResolveDependency
在该方法中调用了
DefaultListableBeanFactory#resolveMultipleBeans
来判断属性需要注入的是多值的从容器中【暂时认为全部都是从容器找到的】找到并直接返回,如果返回null则继续调用
DefaultListableBeanFactory#findAutowireCandidates
找到所匹配的注入类型,封装为map,beanName-》class

这里之所以是返回class而不是实例可能是因为可能有多个实例后面通过name又没匹配上
//从而浪费了实例化,因为实例化生命周期非常复杂,所以等到后面name匹配成功,再根据class去实例化

通过类型找到多个class,1、是否标记了主要如@Primary,2、是否有排序,3、最后一个策略,注入值已存在或者名称匹配,最终得到一个符合的实例/目标class
最后能正常拿到值如果还是class则实例化再返回如果不是直接返回该对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值