Spring Bean创建和循环依赖
作者:? 发布时间:2023-10-21 09:17:51
1 前言
前文已经讲述了Spring BeanFactory 与 FactoryBean 的区别详情,在本文中将继续讲解 Bean 的创建和初始化,在这个环节中将会涉及到 Bean 的创建、初始化和循环依赖内容。
2 Bean 的创建
在前文中已经讲述了 Spring 容器启动的核心方法 refresh,关于 Bean 的创建和初始化方法都是在 finishBeanFactoryInitialization()
中进行处理,在这个阶段就是处理所有剩余的非懒加载的单例对象。
在该方法中,调用 preInstantiateSingletons()
进行 Bean 的所有单实例 bean。 在这个过程中,会获取容器中的所有 Bean, 依次进行初始化和创建对象。获取所有的 Bean 定义信息 beanDefinitionNames
。在处理 Bean 时需要判断 Bean 定义信息是不是抽象的,单例,和懒加载。其核心方法为 getBean , 也许大家都知道在获取 Bean 的过程中,会经历 getBean -> doGetBean -> createBean -> doCreateBean
方法调用链,在 Spring 源码中, doXXX 的方法都是实际业务的方法,在 doCreateBean
方法中,createBeanInstance
方法是真实创建 Bean 对象的方法,在 Spring 中,都是采用反射的方法来创建对象的。这些核心的方法都是在 AbstractAutowireCapableBeanFactory
中实现,下图便是 doCreateBean 方法,其中的核心操作有三个: createBeanInstance 、populateBean、initializeBean
。
createBeanInstance
createBeanInstance
是创建 Bean 对象的方法,这里最终调用的是 instantiateBean
方法,最终的调用栈如下:
AbstractAutowireCapableBeanFactory.instantiate
-> SimpleInstantiationStrategy.instantiate
-> BeanUtils.instantiateClass
-> ctor.newInstance
populateBean
populateBean
是设置 Bean 属性的方法,如下图所示 autowireByName
和 autowireByType
两个方法即是自动注入的方法,以 autowireByName 为例,获取属性是以 getBean 的方式从 IOC 容器中获取对应的 Bean。
initializeBean
初始化 Bean 是在实例化之后的操作,在初始化之前和之后便是 BeanPostProcessor
的操作,初始化的操作便是 invokeInitMethods
的初始化方法。
# 在初始化之前和之后执行
applyBeanPostProcessorsBeforeInitialization
applyBeanPostProcessorsAfterInitialization
初始化 Bean 的操作
初始化之前和之后的操作方法:
循环依赖问题
循环依赖是绕不开的话题,循环依赖的问题具体的表现形式如下:
在讲循环依赖如何结果之前,还是涉及到 Bean 是如何创建的,如下图所示的过程就是解决循环依赖的过程。
1 在创建 A 对象时,需要在 populateBean 填充属性时触发获取 B 对象的操作,这里说一下会在 createBeanInstance 方法中将对象的构造方法放进 * 缓存中。
2 在经历了一轮 getBean 和 createBean 之后再次执行到属性赋值操作 populateBean,此时会再次触发获取 A 对象的操作,此时再去获取 A 对象时,会从 * 缓存中创建一个半成品 A 对象放进二级缓存中并删除 * 缓存,并做返回,此时 B 对象得到属性填充,完成赋值后放进一级缓存中,并将 B 对象返回到 1 步骤。
3 第一步的创建 A 对象继续,完成属性赋值后,会将对象放进一级缓存中,并删除二级缓存。 创建 Bean 的过程如下图所示,
Abstra ctAutowireCapableBeanFactory.doCreateBean
方法核心内容如下:
获取单例 Bean 的方法:
初始化的方法如下所示:
通过以上的三个步骤,就实现了循环依赖的问题解决,也完成了 Bean 对象的创建过程。
为什么要使用 * 缓存呢,说到底是要解决以下问题:
1 如果采用了一级缓存,如果没有存在循环依赖的问题,确实是可以的。如果有存在前图中的循环依赖问题,那么就无法解决了,就只能采用两级缓存才能解决了。
2 如果使用了两级缓存,确实能解决一部分的问题。但是 Bean 被 AOP 代理,再使用两级缓存就不能解决问题了,必须采用 * 缓存。
来源:https://juejin.cn/post/7083689894089850893
猜你喜欢
- Spring Framework 提供了一套可以方便地对 Controller 层中接收的参数进行校验的框架,其中就包括了 @Validat
- 前几天有个客户在系统上写了一段html语句,打开页面就显示一张炒鸡大的图片,影响美观。后来仔细想想,幸亏注入的仅仅是html语句,知道严重性
- Maven搭建springboot项目本文是基于Windows 10系统环境,使用Maven搭建springboot项目Windows 10
- OAuth 简介OAuth 是由 Blaine Cook、Chris Messina、Larry Halff 及 David Recordo
- 目录 - JWT- JWT与其它的区别OAuthCookie/Session Auth- JWT的优点- 认证- JWT的缺点-
- 前言在 Java 开发领域,热部署一直是一个难以解决的问题,目前的 Java 虚拟机只能实现方法体的修改热部署,例如使用devtool来实现
- Mybatis的日志模块的适配器模式我们在开发中日志是必不可少的一部分,而市场中有很多日志框架供我们使用,mybatis作为一个开源框架需要
- 编写一个简单的mybatis进行插入数据的实例1 数据库建表 其中建表dob=Date of Birth 的意思create table s
- 引言最近在写一个 Mybatis 代码自动生成插件,用的是Mybatis来扩展,其中有一个需求就是 生成javaMapper文件和 xmlM
- 目录1.@ 根据id更新2.@ 条件构造器作为参数进行更新3.@ lambda构造器mybatisplus update语句为null时没有
- JSON.toJSONString()空字段不忽略修改使用JSON.toJSONString(object)方法,返回的json中,默认会将
- java遍历json字符串,取得相应KV值时,各种麻烦,比如将json中的list取出来转为JSONArray,再将list中的object
- 完整代码已上传到GitHub。Web端体验地址:http://47.116.72.33/(只剩一个月有效期)apk下载地址:https://
- 上一节我们了解了Lock接口的一些简单的说明,知道Lock锁的常用形式,那么这节我们正式开始进入JUC锁(java.util.concurr
- 前言属于基础的面试问题,一定要能够回答全哦~一、继承Thread,重写run方法通过自定义一个类(这里起名为:MyThread),继承Thr
- 1 问题手写一个程序,完成List集合对象的逆序遍历2 方法创建List接口的多态对象向创建好list集合添加元素使用hasPrevious
- 最近因为fastjson安全漏洞,升级jar包时,踩了一些坑。新版本FastJsonHttpMessageConverter初始化,默认设置
- 概述从今天开始, 小白我将带大家开启 Jave 数据结构 & 算法的新篇章.循环队列循环队列 (Circular Queue) 是一
- 添加群机器人可以查看这篇文章:添加机器人到钉钉群 使用命令行工具curl快速验证自定义机器人是否可以正常工作。可以使用如下命令,把对应的链接
- 一、什么是抽象工厂模式为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。抽象工厂模式是所有形态的工厂模式中最为抽象和最具