实例化方法,把bean实例化,并且包装成BeanWrapper

1、点进这个方法里面。

这个方法是反射调用类中的 factoryMethod 方法。 这要知道@Bean 方法的原理, 实际上
spring 会扫描有@bean 注解的方法, 然后把方法名称设置到 BeanDefinition 的 factoryMethod
属性中, 接下来就会调到上面截图中的方法实现@Bean 方法的调用。 
2、 有参构造函数的时候

determineConstructorsFromBeanPostProcessors
这个方法是 BeanPostProcessor 接口类的首次应用, 最终会掉到
AutowiredAnnotationBeanPostProcessor 类的方法, 在方法中会扫描有注解的构造函数然后完
成装配过程。 然后把有有@Autowired 注解的构造函数返回。

3、 无参构造函数的实例化

这就是简单的反射实例化。 大部分类的实例化都会走这个逻辑
4、 类中注解的收集
实例化完成后接下来就需要对类中的属性进行依赖注入操作, 但是类里面属性和方法的依
赖注入往往用@Autowired 或者@Resource 注解, 那么这些注解的依赖注入是如何完成的
呢?
注解的收集:

也是通过 BeanPostProcessor 接口类型实例来挨个处理的。
A、 首先是
CommonAnnotationBeanPostProcessor 类, 这个类完成了@Resource 注解的属性或
者方法的收集
这个类还对@PostConstruct 和@PreDestory 支持

收集过程
1、 看缓存里面有没有 InjectionMetadata 对象
2、 从类中获取所有 Field 对象, 循环 field 对象, 判断 field 有没有@Resource 注解,
如果有注解封装成 ResourceElement 对象
3、 从类中获取所有 Method 对象, 循环 Method 对象, 判断 Method 有没有@Resource
注解, 如果有注解封装成 ResourceElement 对象
4、 最终把两个 field 和 Method 封装的对象集合封装到 InjectionMetadata 对象中

B、 然后是
AutowiredAnnotationBeanPostProcessor 类, 对@Autowired 注解的属性和方法
的收集。 收集过程基本上跟@Resource 注解的收集差不多, 这里就不赘述了

5、 IOC\DI 依
对应的方法:

这里又是一个 BeanPostProcessor 类型接口的运用, 前面我们讲到了@Resource@Autowired 注解的收集, 那么这个方法就是根据收集到的注解进行反射调用。 

 循环收集到的 metaData 中的 list 对象, 然后挨个调用里面的 InjectedElement 的inject 方法完成依赖注入。 

其中 value 值的获取, 如果依赖的属性是一个引用类型必定会触发该属性的
BeanFactory.getBean 操作, 从而从 spring 容器中获取到对应的实例。 方法的依赖注
入类似这里就不再赘述。

6、 bean 实例化后的操作
代码走到这里:

A、 首先是对某些 Aware 接口的调用

B、 然后@PostConstruct 注解方法的调用

这里又是一个 BeanPostProcessor 接口的运用,
前面讲过, 有@PostConstruct 注解的方法会收集到一个 met
就是通过 BeanPostProcessor 接口调到
CommonAnnotationBeanPostProcessor 类, 然后在类中拿
根据对象里面的容器来反射调用有注解的方法。 代码如下:

 有@PostConstruct 注解的容器会收集到 initMethods 容器中, 接下来就是方法的

反射调用。

C、 InitializingBean 接口和 init-method 属性调用

Init-method 属性调用是在 afterPropertiesSet 之后

afterPropertiesSet和Init-method和有@PostConstruct注解的方法其实核
心功能都是一样的, 只是调用时序不一样而已, 都是在该类实例化和 IOC 做完后调用
的, 我们可以在这些方法中做一些在 spring 或者 servlet 容器启动的时候的初始化
工作。 比如缓存预热, 比如缓存数据加载到内存, 比如配置解析, 等等初始化工作。
在这个方法里面还有一个重要的逻辑

也是一个 BeanPostProcessor 接口的运用, 在这里会返回 bean 的代理实例, 这个
就是 AOP 的入口。
D、 FactoryBean 接口
带入如下:

在实例化和 IOC/DI 做完后, 就会调用 FactoryBean 类型的接口, 如果要获取到
FactoryBean 类本身, 就必须加上”&”符号, 比如
beanFactory.getBean(“&beanName” )。

BeanFactory.getBean(“beanName” )只能获取到 getObject()方法返回的实
例。
getObject 方法返回的实例会有单独的缓存存储, 跟其他实例不是同一个缓存, 对应的缓
存是: factoryBeanObjectCache

E、 循环依赖
循环依赖请参照流程图理解
https://www.processon.com/view/link/5df9ce52e4b0c4255ea1a84f
循环依赖只会出现在单例实例无参构造函数实例化情况下
有参构造函数的加@Autowired 的方式循环依赖是直接报错的, 多例的循环依赖也是
直接报错的

循环依赖步骤:
1、 A 类无参构造函数实例化后, 设置三级缓存
2、 A 类 populateBean 进行依赖注入, 这里触发了 B 类属性的 getBean 操作
3、 B 类无参构造函数实例化后, 设置三级缓存
4、 B 类 populateBean 进行依赖注入, 这里触发了 A 类属性的 getBean 操作
5、 A 类之前正在实例化, singletonsCurrentlyInCreation 集合中有已经
有这个 A 类了, 三级缓存里面也有了, 所以这时候是从三级缓存中拿到的提前暴露的
A 实例, 该实例还没有进行 B 类属性的依赖注入的, B 类属性为空。
6、 B 类拿到了 A 的提前暴露实例注入到 A 类属性中了
7、 B 类实例化已经完成, B 类的实例化是由 A 类实例化中 B 属性的依赖注入触发
的 getBean 操作进行的, 现在 B 已经实例化, 所以 A 类中 B 属性就可以完成依赖注
入了, 这时候 A 类 B 属性已经有值了
8、 B 类 A 属性指向的就是 A 类实例堆空间, 所以这时候 B 类 A 属性也会有值了。

spring源码之bean的初始化及循环引用的更多相关文章

  1. Spring源码-IOC部分-容器初始化过程【2】

    实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...

  2. Spring源码系列 — Bean生命周期

    前言 上篇文章中介绍了Spring容器的扩展点,这个是在Bean的创建过程之前执行的逻辑.承接扩展点之后,就是Spring容器的另一个核心:Bean的生命周期过程.这个生命周期过程大致经历了一下的几个 ...

  3. Spring源码系列 — 构造和初始化上下文

    探索spring源码实现,精华的设计模式,各种jdk提供的陌生api,还有那么点黑科技都是一直以来想做的一件事!但是读源码是一件非常痛苦的事情,需要有很大的耐心和扎实的基础. 在曾经读两次失败的基础上 ...

  4. Spring源码之Bean生命周期

    https://www.jianshu.com/p/1dec08d290c1 https://www.cnblogs.com/zrtqsk/p/3735273.html 总结 将class文件加载成B ...

  5. Spring 源码学习 04:初始化容器与 DefaultListableBeanFactory

    前言 在前一篇文章:创建 IoC 容器的几种方式中,介绍了四种方式,这里以 AnnotationConfigApplicationContext 为例,跟进代码,看看 IoC 的启动流程. 入口 从 ...

  6. Spring源码 21 Bean生命周期

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  7. 【spring源码】bean的实例化(转载)

    首先来看一段代码,看过上一节的朋友肯定对这段代码并不陌生.这一段代码诠释了Spring加载bean的完整过程,包括读取配置文件,扫描包,加载类,实例化bean,注入bean属性依赖. 上一节介绍了Sp ...

  8. Spring源码学习

    Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...

  9. Spring源码-IOC部分-Spring是如何解决Bean循环依赖的【6】

    实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...

随机推荐

  1. Http请求的三个常见问题

    我们做的大多数项目,必不可少的需要向后台发送请求获取数据,常用的http请求就是post请求和get请求 那么引出一个最常见的问题——Q:post请求和get请求有什么区别? A: 从语义上我们可以这 ...

  2. CentOS7(Linux)源码安装Redis

    介绍 项目中经常需要用到Redis做缓存数据库,可是还有小伙伴不会在Linux上安装Redis,毕竟我们开发的项目都是要在服务器上运行的,今天就来讲讲如何在CentOS7环境使用源码进行安装Redis ...

  3. CSS 段落/换行/缩进

    CSS 段落/换行/缩进 1.盒模型 box-sizing: content-box|border-box|inherit; content-box(默认) : 实际宽度/高度 = width/hei ...

  4. SEO大神都是些什么人

    http://www.wocaoseo.com/thread-97-1-1.html 貌似好久没有更新seo培训联盟的文章了,最近一直在专心学习其他的东西,前一段写了几篇关于用户需求和体验的文章,但是 ...

  5. 【Pod Terminating原因追踪系列之一】containerd中被漏掉的runc错误信息

    前一段时间发现有一些containerd集群出现了Pod卡在Terminating的问题,经过一系列的排查发现是containerd对底层异常处理的问题.最后虽然通过一个短小的PR修复了这个bug,但 ...

  6. guzzle下载图片(laravel+vue)

    先再laravel安装guzzle扩展包:composer require guzzlehttp/guzzle 之后再控制器操作: use GuzzleHttp\Client; //远程api数据的获 ...

  7. Laravel Pipeline原理及使用

    Laravel Pipeline原理及使用 开发中可能遇到非常冗长的逻辑,以至于我们想将针对性逻辑拆分出来,但是又拿不准该如何拆分才能实现较高的扩展性并保证较高的维护性,或者说不知道如何优雅的将待处理 ...

  8. stf-多设备管理平台搭建

    项目地址: https://github.com/openstf/stf 安装.使用命令 # 安装stfbrew install rethinkdb graphicsmagick zeromq pro ...

  9. SpringCloud实战 | 第五篇:SpringCloud整合OpenFeign实现微服务之间的调用

    一. 前言 微服务实战系列是基于开源微服务项目 有来商城youlai-mall 版本升级为背景来开展的,本篇则是讲述SpringCloud整合OpenFeign实现微服务之间的相互调用,有兴趣的朋友可 ...

  10. 笔记 | 第一个量子算法:Deutsch-Jozsa算法,非常好懂!

    <关于胡小兔的博客又诈尸了这件事> 信息物理真是难啊!上节课讲了量子计算的最基础的概念和Deutsch-Jozsa算法,我看了好几天才看懂-- 等考完试估计我就忘了,所以今天先写个博客给未 ...