Spring源码分析之createBean主流程分析

2023-11-03

我们知道,在调用getBean获取bean实例的实例,首先会从缓存中获取bean实例,如果没有获取到,就会去创建bean的时候。关于获取bean实例,可以参考Spring源码分析之getBean主流程分析,而本文将会对创建bean实例的主流程来做一个分析。而入口,当然是createBean(AbstractAutowireCapableBeanFactory)的方法。

下面来看源码:

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) 
			throws BeanCreationException {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating instance of bean '" + beanName + "'");
	}
	RootBeanDefinition mbdToUse = mbd;
	//1:解析bean的类型
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	try {
	//2:处理 lookup-method 和 replace-method 配置,而Spring统称为override method
		mbdToUse.prepareMethodOverrides();
	}
	catch (BeanDefinitionValidationException ex) {
		........
	}

	try {
	//3:bean的后置处理器,如果有,这里会返回代理的实例。AOP的实现基础就是基于这里来实现的
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
	catch (Throwable ex) {
		........
	}
	//来创建bean的实例
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	if (logger.isDebugEnabled()) {
		logger.debug("Finished creating instance of bean '" + beanName + "'");
	}
	return beanInstance;
}

其主流程逻辑也是比较的简单的:

  1. 对bean类型的解析
  2. 处理methodOverrides
  3. 处理bean实例的后置处理器。如果有,则返回一个代理的类。这里实际上是判断类有没有实现InstantiationAwareBeanPostProcessor接口。
  4. 创建实例bean并返回。

下面我们来看看doCreateBean中的逻辑:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
		throws BeanCreationException {
	//bean实例包装类
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		//从缓存中清理相关中的包装类
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		//创建bean的时候,这里创建bean的实例有三种方法
		//1:工厂方法创建
		//2:   利用构造方法的方式注入
		//3:   利用无参构造方法注入
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	//这里的bean应该是才被实例化的bean,还未被填充相关的属性
	final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
	Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
	mbd.resolvedTargetType = beanType;

	synchronized (mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			try {
			applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
				.........
			}
			mbd.postProcessed = true;
		}
	}

	//判断是否是早期引用的bean,如果是,则允许其提前暴露引用
	//这里判断的逻辑主要有三个:
 	//1:是否为单例:isSingleton
	//2:是否允许循环引用 :allowCircularReferences
	//3:是否是在创建中的bean:isSingletonCurrentlyInCreation
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		if (logger.isDebugEnabled()) {
			logger.debug("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
		}
		addSingletonFactory(beanName, new ObjectFactory<Object>() {
			@Override
			public Object getObject() throws BeansException {
				return getEarlyBeanReference(beanName, mbd, bean);
			}
		});
	}

	Object exposedObject = bean;
	try {
		//填充bean的属性
		populateBean(beanName, mbd, instanceWrapper);
		if (exposedObject != null) {
		//初始化bean,过程如下:
		//1:判断是否实现了BeanNameAware,BeanClassLoaderAware以及
		//   BeanFactoryAware方法,如果有,则设置相关的属性
		//2: 调用bean初始化的前置操作
		//3: 执行初始化的方法。
		//	如果有initializingBean,则调用afterPropertiesSet
		//	如果有InitMethod,则调用初始方法
		//4: 调用bean初始化的后置操作
		exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
	}
	catch (Throwable ex) {
		if (ex instanceof BeanCreationException && 
		beanName.equals(((BeanCreationException) ex).getBeanName())) {
			throw (BeanCreationException) ex;
		}
		else {
			throw new BeanCreationException(
		mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
		}
	}
	//解决相关的循环依赖
	if (earlySingletonExposure) {
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			}
			else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
			String[] dependentBeans = getDependentBeans(beanName);
			Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
			for (String dependentBean : dependentBeans) {
				if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
					actualDependentBeans.add(dependentBean);
				}
				}
				if (!actualDependentBeans.isEmpty()) {
					......
				}
			}
		}
	}
	//注册bean的销毁逻辑
	try {
	registerDisposableBeanIfNecessary(beanName, bean, mbd);
	}
	catch (BeanDefinitionValidationException ex) {
		......
	}
	return exposedObject;
}

实际创建bean实例的逻辑如下:

1:创建bean的实例(工厂方法,构造器注入的方式,简单初始化的方式)

2:是否允许其是否提前暴露引用,以便解决循环依赖的问题。

3:填充bean实例的属性

4:初始化操作(初始方法前操作,调用初始化方法,执行初始化后的方法)

5:解决循环依赖相关的问题。

6:注册bean的销毁逻辑。

至此,整个创建bean实例的主流程就分析完成了,下面将以一个简单的图来更加形象的展示其主流程调用逻辑。

创建bean实例流程
南瓜灯cc

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring源码分析之createBean主流程分析 的相关文章

  • sonic 架构学习

    射人先射马 xff0c 擒贼先擒王 在我们学习sonic的过程中 xff0c 无疑了解sonic的架构是非常重要的 xff0c 然后再去了解各个模块的细节 xff0c 总分学习模式 下面是我自我学习并翻译的链接https github co
  • VIPER架构学习

    VIPER架构学习探索 编程准则资源下载什么是VIPER功能快捷键合理的创建标题 xff0c 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中 居左 居右SmartyPan
  • EncodedResource类解读

    EncodedResource类解读 EncodedResource介绍 EncodedResource是spring中Resource编码相关的封装类 EncodedResource里面封装了一个Resource成员属性 其实主要功能就是
  • 【Spring源码】createBean()

    目录 1 resolveBeanClass 2 prepareMethodOverrides 3 resolveBeforeInstantiation 1 applyBeanPostProcessorsBeforeInstantiation
  • Spring源码之事件监听机制(下)

    文章目录 前言 一 手写事件监听机制框架 1 准备 2 事件监听接口 3 事件管理器 4 事件发布器 5 需求 6 编码 二 观察者模式 1 概述 2 UML图 3 Coding验证 小结 前言 这篇文章接的是上篇文章Spring源码之事件
  • 【Spring源码】BeanPostProcessor

    org springframework beans factory support AbstractAutowireCapableBeanFactory 八次调用时机 1 是否需要代理 resolveBeforeInstantiation
  • Spring事务(三)——传播属性之REQUIRED

    事务是与连接对象紧密相关的 事务属性用来控制事务流转 Spring事务的传播属性有以下几种 Propagation REQUIRED 如果当前没有事务 就新建一个事务 如果已经存在一个事务中 则加入到这个事务中 默认属性 也是最常使用 Pr
  • Spring源码分析之createBean主流程分析

    我们知道 在调用getBean获取bean实例的实例 首先会从缓存中获取bean实例 如果没有获取到 就会去创建bean的时候 关于获取bean实例 可以参考Spring源码分析之getBean主流程分析 而本文将会对创建bean实例的主流
  • spring源码之@Autowired属性注入

    注入现象 当我们在属性上面加上 Autowired的时候 spring就要根据Type来注入实例了 那么到底会找哪个实例的如果有多个怎么办 今天就来实验一下 多接口注入 当注入的属性接口下有多个实现 这个时候运行的话是 public cla
  • cglib动态代理实现原理详细分析

    在之前Java代理模式中大致的分析了下代理模式的类型及对每种代理类型简单的举例了下 在上篇JDK动态代理实现原理详细分析中 对其JDK代理的流程做了一个详细的分析 而本文 将介绍另一种动态代理模式 cglib动态代理 阅读完本文 你将对cg
  • 详解分布式共识(一致性)算法Raft

    分布式共识及Raft简介 所谓分布式共识 consensus 与CAP理论中的一致性 consistency 其实是异曲同工 就是在分布式系统中 所有节点对同一份数据的认知能够达成一致 保证集群共识的算法就叫共识算法 它与一致性协议这个词也
  • spring加载流程之ConfigurationClassPostProcessor

    spring加载流程之ConfigurationClassPostProcessor ConfigurationClassPostProcessor postProcessBeanDefinitionRegistry processConf
  • Spring之启动过程源码解析

    Spring创建Bean 会经过一系列生命周期的流程 而Spring启动 其实就是为了后续创建Bean做一些准备工作 本篇以及下一篇文章都是来详细分析Spring的启动过程 目录 一 Spring启动的大致流程 二 Spring加载流程之A
  • 架构基础概念

    系统 系统泛指一群有 关联 的个体组成 根据某种 规则 运作 能完成个别元件不能单独完成 的工作群体 子系统 其实子系统也是由一群有关联的个体所组成的系统 多半是更大系统中的一部分 模块 软件模块是一套一致而互相有紧密关联的软件组织 它分别
  • 深入分析RestController与Controller

    RestController和 Controller注解 我们都知道RestController默认都只提供Rest风格接口返回值 针对不需要返回页面的Controller都采用RestController进行注解 下面根据源码简单分析一下
  • IDEA导入Spring源码环境搭建

    一 环境准备 1 Spring源码包 下载地址 https github com spring projects spring framework 2 gradle工具 下载地址 http downloads gradle org dist
  • Spring源码:PropertyValues类及属性注入二

    主代码 1 RuntimeBeanReference类型 2 RuntimeBeanNameReference类型 3 BeanDefinitionHolder类型 4 BeanDefinition类型 5 ManagedArray类型 6
  • 四、spring源码循环依赖的处理之doCreateBean方法的执行流程(文字描述)

    还写了一篇 内容和这个差不多的 emm 那篇更简洁 算是半伪码形式 https blog csdn net qq 36951116 article details 100078947 其实createBean方法没做什么事 主要就是 1 调
  • Spring源码之Bean的生命周期

    Spring已经成为了目前最流行的第三方开源框架之一 我们在充分享受Spring IOC容器带来的便捷时 也应该考虑一下Spring这个大工厂是如何将一个个的Bean生产出来的 我们一起来讨论一下Spring中Bean的生命周期 Sprin
  • Spring之循环依赖源码解析

    目录 1 什么是循环依赖 2 为什么会出现循环依赖 3 面对循环依赖问题 我们该如何思考解决 4 Spring是怎么解决循环依赖的 5 总结 1 什么是循环依赖 有两个类Order Customer Order对象依赖了Customer对象

随机推荐

  • OD(Ollydbg)简介

    ollydbg简介 Ollydbg 通常称作OD 是反汇编工作的常用工具 OD附带了200脱壳脚本和各类插件 功能非常强大 可以过SE VMP3 0 深受逆向圈内人士的喜爱 OD 是一个反汇编工具 又叫OllyDebug 一个新的动态追踪工
  • 源码、反码、补码

    接下来的一章会提到位操作符 所以我们先介绍一下这三种二进制形式 整数的二进制表示形式 一共有三种 源码 反码 补码 1 正整数的原码 反码和补码都是相同的 2 负整数的原码 补码和反码是要经过计算的 首先 不管是正整数还是负整数都可以直接写
  • GateWay启动报错:Error processing condition on org.springframework.cloud.gateway.config.GatewayAutoConfig

    错误 java lang IllegalStateException Error processing condition on org springframework cloud gateway config GatewayAutoCon
  • 15.线程同步的几种方法

    一 为什么需要线程同步 线程同步通常是出现在多线程环境下的问题 对于多个线程同时访问的共享内存中的变量 如果不进行保护 就会导致一些列数据出错问题 以下图为例 假设线程A在第一次读取变量的值为10 每次写周期会将变量A加5 理论上当线程A完
  • mysql主键id的生成方式(自增、唯一不规则)

    1 利用uuid函数生成唯一且不规则的主键id sql CREATE TABLE test id varchar 100 COLLATE utf8 estonian ci NOT NULL COMMENT 唯一不重复 create time
  • AIX软件安装的相关命令

    文件集 Filesets AIX操作系统的最小可安装单元软件包 Packages 软件包由一组可独立安装的文件集组成注册的程序产品 LPP LPP包含所有与该注册的程序相关联的软件包 软件束 Bundles 一组软件 包含文件集 软件包和L
  • moment.js 时间处理的使用方法--含有CDN链接

    范例 https cybozudev kf5 com hc kb article 211149 CDN链接 https cybozudev kf5 com hc kb article 206405
  • ORACLE等待事件类型(一)

    author skate tiime 2009 11 18 ORACLE等待事件类型 Classes of Wait Events 每一个等待事件都属于某一类 下面给出了每一类等待事件的描述 Every wait event belongs
  • linux模拟网络丢包、延迟、数据包损坏

    环境 工具 linux TC tc默认系统自带 只对物理网卡生效 不对虚拟网卡生效 如果对关联了虚拟网卡的物理网卡使用会同时生效 模拟网络延迟 tc qdisc add dev eth0 root netem delay 1000ms ro
  • 解读es6 class 中 constructor 方法 和 super 的作用

    ES6 的 class 属于一种 语法糖 所以只是写法更加优雅 更加像面对对象的编程 其思想和 ES5 是一致的 类和模块的内部 默认就是严格模式 所以不需要使用use strict指定运行模式 定义类 class Point constr
  • c++ 文件类型判断

    要判断文件类型 即判断文件名是否包含文件的后缀 例如 txt文件的判断 string str abcd txt string str1 txt 当 str find str1 string npos时则说明字符串str中不存在 txt 这个
  • MonoField MonoReflectionField FieldInfo

    mono mcs class corlib System Reflection MonoField cs StructLayout LayoutKind Sequential internal class MonoField RtField
  • 环形链表问题

    题目 给定一个链表的头节点 head 返回链表开始入环的第一个节点 如果链表无环 则返回 null 如果链表中有某个节点 可以通过连续跟踪 next 指针再次到达 则链表中存在环 为了表示给定链表中的环 评测系统内部使用整数 pos 来表示
  • linux 软件安装各种方法

    一 简单介绍 1 软件安装卸载 分几种情况 A RPM包 这种软件包就像windows的EXE安装文件一样 各种文件已经编译好 并打了包 哪个文件该放到哪个文件夹 都指定好了 安装非常方便 在图形界面里你只需要双击就能自动安装 如何卸载 1
  • SE-ResNet的实现

    见 D pythonCodes 深度学习实验 4 1 经典分类网络 inference代码汇总 models se resnet py 一 SE ResNet的实现方法 读了senet这篇论文之后 可以知道senet并没有提出一个新的网络
  • Easyui combobox 判断输入项是否存在于下拉列表中

    combobox的getValue方法很诡异 当输入项是存在于下拉列表时 返回的是需要的ID 但是当输入项是不存在于下拉列表时 却直接返回用户的输入结果 从而导致没法判断用户是否输入了下拉框不存在的项 本来第一时间想到直接判断getValu
  • 蓝绿发布、滚动发布、灰度发布,有什么区别?

    目录 01 蓝绿发布 02 滚动发布 03 灰度发布 04 A B测试 在项目迭代的过程中 不可避免需要 上线 上线对应着部署 或者重新部署 部署对应着修改 修改则意味着风险 目前有很多部署发布的技术 这儿将常见的做一个总结 举一个情景例子
  • 第一次使用Xshell服务器跑程序(保姆教程)

    前期准备 1 提前下载好Xshell和Xftp 2 有自己的服务器账号名 密码 服务器IP 默认端口号 我的是组里师兄给我创建的 以上两步下载注册步骤可以参考文章1和文章2 3 我的服务器默认安装好了Anaconda3和cuda11 1 1
  • Flutter之状态管理Provider使用和详解

    在前端页面 状态管理和消息传递一直是我们开发一个交互性好 体验好的前端应用或者APP必须要提到的东西 设想一下我们需要两个组件之间共享数据 而且两个组件之间具有联动效果 对于Flutter来说我们能够把数据保存到一个全局变量 然后每次使用的
  • Spring源码分析之createBean主流程分析

    我们知道 在调用getBean获取bean实例的实例 首先会从缓存中获取bean实例 如果没有获取到 就会去创建bean的时候 关于获取bean实例 可以参考Spring源码分析之getBean主流程分析 而本文将会对创建bean实例的主流