Spring源码学习笔记9——构造器注入及其循环依赖

一丶前言

前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在循环依赖问题上构造器注入常被说spring无法解决构造器注入的循环依赖,下面我们来分析构造器注入和其循环依赖的源码

二丶构造器依赖注入

在spring初始化每一个非抽象,单例,非懒加载的bean的时候,会调用createBeanInstance方法去创建bean的实例,在使用默认的策略——无参构造or CGLIB生成子类对象的方式之前,先会使用所有的SmartInstantiationAwareBeanPostProcessor 来判断是否有用户指定的后置处理器

1.循环调用所有的SmartInstantiationAwareBeanPostProcessor实现类来推断该使用哪个构造器

这里重点是使用到了AutowiredAnnotationBeanPostProcessor来推断

2.AutowiredAnnotationBeanPostProcessor 推断构造器的逻辑

首先AutowiredAnnotationBeanPostProcessor 有一个缓存key是bean类型,value是之前推断的所有构造器数组。自然是一波双if+synchronized方式来读缓存中内容,缓存没有命中再进行推断

遍历每一个构造器(这里省去了spring对Kotlin语言支持的部分)
1.获取当前构造器上面的@Autowired 和 @Value 注解
2.如果注解信息为空,且当类是一个被CGLIB代理后的类,
会获取父类构造器上面的注解(要求父类构造器和当前遍历到的构造器参数类型顺序相同)
3.如果注解信息不为空,会检查 required 属性的信息
(spring还支持ejb等的注解,所有这里检查require的信息)像@Autowired 和 @Value这种不包含required属性的注解会默认是required为true,
并且记录当前构造器为候选者,也就是说有注解的才算在候选者
4.如果存在多个required=true的构造器抛出异常,
否则使用遍历记录当前required=true的构造器
5.如果候选者不为空,required=true的构造器为空
(一般这种情况是标注了EJB的注解指定required为false)spring会把无参构造加入到候选者中
6.如果原来类只定义了一个有参构造,那么使用这个有参构造 如果不考虑EJB中的依赖注入注解
那么就是如果构造器有@Autowired or @Value那么默认使用它
如果定义了一个有参构造那么使用这个有参构造 其他情况一律返回null(后续spring可能使用无参构造or CGLIB生成子类的方式)

3.使用构造器进行依赖注入的逻辑

推断出使用哪个构造器之后,spring调用autowireConstructor方法进行构造器注入,具体逻辑委托给ConstructorResolver的autowireConstructor方法,最终解析依赖注入参数的在createArgumentArray方法中进行,一般是调用resolveAutowiredArgument方法

最终还是殊途同归的调用到了beanFactory的resolveDependency方法

4.实例化对象

这一步还是调用的instantiate方法

三丶为什么构造器的循环依赖spring无法解决

1.构造方法注入无法解决循环依赖的情况及其原因

如果是这种循环依赖的情况spring是无法解决循环依赖的,下面是这种循环依赖出现时候的代码流程

问题出现在beforeSingletonCreation方法中

在spring创建bean的之前使用了set维护正在创建bean的名称,B需要A,再次创建A的时候就发现set中原本存在A,这时候就是无法解决循环依赖的情况,会抛出异常

同理这种情况也是不可以解决的

2.构造方法注入可以解决循环依赖的情况及其原因

这种情况下spring又是可以解决循环依赖的



原因是A是可以成功使用无参构造实例化的,所以B需要A的时候可以在三级缓存拿到A的ObjectFactory,调用后得到A,而不是再次创建A

我们可以得到结论

如果加载顺序是A然后B,那么A只能是字段注入or方法注入,不能是构造器注入
B无所谓那种注入方式

Spring源码学习笔记9——构造器注入及其循环依赖的更多相关文章

  1. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  2. Spring 源码学习笔记10——Spring AOP

    Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...

  3. Spring 源码学习笔记11——Spring事务

    Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...

  4. spring源码学习笔记之容器的基本实现(一)

    前言 最近学习了<<Spring源码深度解析>>受益匪浅,本博客是对学习内容的一个总结.分享,方便日后自己复习或与一同学习的小伙伴一起探讨之用. 建议与源码配合使用,效果更嘉, ...

  5. Spring源码学习笔记之bean标签属性介绍及作用

    传统的Spring项目, xml 配置bean在代码中是经常遇到, 那么在配置bean的时候,这些属性的作用是什么呢? 虽然说现在boot项目兴起,基于xml配置的少了很多, 但是如果能够了解这些标签 ...

  6. Spring源码学习笔记之基于ClassPathXmlApplicationContext进行bean标签解析

    bean 标签在spring的配置文件中, 是非常重要的一个标签, 即便现在boot项目比较流行, 但是还是有必要理解bean标签的解析流程,有助于我们进行 基于注解配置, 也知道各个标签的作用,以及 ...

  7. 【spring源码系列】之【Bean的循环依赖】

    希望之光永远向着目标清晰的人敞开. 1. 循环依赖概述 循环依赖通俗讲就是循环引用,指两个或两个以上对象的bean相互引用对方,A依赖于B,B依赖于A,最终形成一个闭环. Spring循环依赖的场景有 ...

  8. Spring源码学习笔记1

    1.Spring中最核心的两个类 1)DefaultListableBeanFactory XmlBeanFactory继承自DefaultListableBeanFactory,DefaultLis ...

  9. Spring源码学习笔记2

    1.默认标签的解析 对四种不同标签的解析 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate dele ...

随机推荐

  1. 基于.NetCore开发博客项目 StarBlog - (5) 开始搭建Web项目

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  2. 824. Goat Latin - LeetCode

    Questioin 824. Goat Latin Solution 题目大意:根据要求翻译句子 思路:转换成单词数组,遍历数组,根据要求转换单词 Java实现: 用Java8的流实现,效率太低 pu ...

  3. CentOS7防火墙firewalld的配置

    开机启动的开启与禁止 # 开机启动 systemctl enable firewalld # 禁止开机启动 systemctl disable firewalld 基本操作 # 查看状态 system ...

  4. pymysql.err.OperationalError: (1054, "Unknown column 'aa' in 'field list'")(已解决)

    错误描述: 今天使用python连接mysql数据库进行数据添加时,出现报错"pymysql.err.OperationalError: (1054, "Unknown colum ...

  5. 国内GPU 厂商产品分布

    抽空理了理国内目前已知显卡厂商的各类产品(来源与各个公司产品网站),可能不全,后续会实时更新. 目前来看,显卡市场还是国外两巨头+intel 占据了绝大数的市场,intel 在igpu上深耕了很多年, ...

  6. 接口测试postman深度挖掘应用②

    上一篇文章我们已经介绍了postman的基本用法,以及接口测试原理.未关注博主的可以关注下博主,后期测试安全,以及各种工具用法,编程语言都会有讲解的 老样子:①先补习基础知识:  ②补充上一章节由于过 ...

  7. JavaScript Object学习笔记二

    Object.create(proto, [propertiesObject])//创建对象,使用参数一来作为新创建对象的__proto__属性,返回值为在指定原型对象上添加自身属性后的对象 //参数 ...

  8. easy-captcha生成验证码

    通常一些网页登陆时,都需要通过验证码去登录: 生成验证码的方法有很多,这次分享一个验证码即能是汉字的 又能是算术的. 首先maven坐标: <dependency> <groupId ...

  9. Linux文本搜索及截取操作

    Linux文本搜索及截取操作 cat 查看 grep 搜索 awk 截取 查看dna-server.xml 文件的内容 [root@localhost servers]# cat cwag9002/w ...

  10. Vue回炉重造之如何使用props、emit实现自定义双向绑定

    下面我将使用Vue自带的属性实现简单的双向绑定. 下面的例子就是利用了父组件传给子组件(在子组件定义props属性,在父组件的子组件上绑定属性),子组件传给父组件(在子组件使用$emit()属性定义一 ...