Spring源码学习笔记9——构造器注入及其循环依赖
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——构造器注入及其循环依赖的更多相关文章
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- Spring 源码学习笔记10——Spring AOP
Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...
- Spring 源码学习笔记11——Spring事务
Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...
- spring源码学习笔记之容器的基本实现(一)
前言 最近学习了<<Spring源码深度解析>>受益匪浅,本博客是对学习内容的一个总结.分享,方便日后自己复习或与一同学习的小伙伴一起探讨之用. 建议与源码配合使用,效果更嘉, ...
- Spring源码学习笔记之bean标签属性介绍及作用
传统的Spring项目, xml 配置bean在代码中是经常遇到, 那么在配置bean的时候,这些属性的作用是什么呢? 虽然说现在boot项目兴起,基于xml配置的少了很多, 但是如果能够了解这些标签 ...
- Spring源码学习笔记之基于ClassPathXmlApplicationContext进行bean标签解析
bean 标签在spring的配置文件中, 是非常重要的一个标签, 即便现在boot项目比较流行, 但是还是有必要理解bean标签的解析流程,有助于我们进行 基于注解配置, 也知道各个标签的作用,以及 ...
- 【spring源码系列】之【Bean的循环依赖】
希望之光永远向着目标清晰的人敞开. 1. 循环依赖概述 循环依赖通俗讲就是循环引用,指两个或两个以上对象的bean相互引用对方,A依赖于B,B依赖于A,最终形成一个闭环. Spring循环依赖的场景有 ...
- Spring源码学习笔记1
1.Spring中最核心的两个类 1)DefaultListableBeanFactory XmlBeanFactory继承自DefaultListableBeanFactory,DefaultLis ...
- Spring源码学习笔记2
1.默认标签的解析 对四种不同标签的解析 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate dele ...
随机推荐
- ThreadLocal夺命11连问
前言 前一段时间,有同事使用ThreadLocal踩坑了,正好引起了我的兴趣. 所以近期,我抽空把ThreadLocal的源码再研究了一下,越看越有意思,发现里面的东西还真不少. 我把精华浓缩了一下, ...
- vue项目引入TinyMCE
1.安装 npm install @tinymce/tinymce-vue@3.0.1 -S 2.配置 <template> <!-- 富文本 --> <div> ...
- 好客租房49-组件的props(特点)
特点 1可以给组件传递任意类型的数据 2props是只读的对象 只能读取属性的值 无法修改对象 3注意:使用类组件时 如果写了构造函数 应该将props传递给super() 否则 无法在构造函数 中获 ...
- Sentinel介绍与使用 收藏起来
点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 sentinel,即可免费获取源码 前言 在家休息的的时候,突然小勇打 ...
- 无法启动报,To install it, you can run: npm install --save @/components/xxxx.vue
运行的过程中后台报错 npm install --save @/components/xxx.vue 重装了node_modules依然没有用. 其实是组件路径写错了 总结 以后出现提醒安装那个vue ...
- 04C++核心编程(二-泛型编程)
Day08 笔记 1 函数模板 1.1 泛型编程 – 模板技术 特点:类型参数化 1.2 template< typename T > 告诉编译器后面紧跟着的函数或者类中出现T,不要报错, ...
- Python 微博搜索爬虫
微博搜索爬虫 网页分析 由于网页端反爬虫机制比较完善所以才去移动端进行爬虫. url地址:https://m.weibo.cn/ 搜索框,输入关键词进行搜索 对网页进行抓包,找到相关数据 查看数据是否 ...
- Django+Vue+Nginx+Https域名代理访问
Django+Vue使用Nginx实现Https域名的安全访问 前端 VUE 前端访问自身域名: https://demo.com,后序使用 Nginx 代理至后端 直接访问后端https:api会无 ...
- Linux系统sed命令常用参数实战
Linux系统sed命令常用参数实战 常用参数 -n 输出某行的文本内容,通常与p联合使用, -e 命令行模式下进行sed的动作编辑,输出编辑后的内容,源文件不会发生变化 -f 以命令中指定的scri ...
- C++ 炼气期之数据是主角
1. 前言 数据在程序中的重要性,怎么强调都不为过,程序的本质就是通过提供数据处理逻辑,把数据从一种状态变成另一种状态的过程.处理逻辑一定是有针对性的,针对的是数据本身的特性. 只有了解了数据本身的内 ...