当前位置: 首页 > news >正文

spring源码篇(3)——bean的加载和创建

spring-framework 版本:v5.3.19

文章目录

  • bean的加载
  • bean的创建
  • 总结
    • getBean流程
    • createBean流程
      • doCreateBean流程

bean的加载

beanFactory的genBean最常用的一个实现就是AbstractBeanFactory.getBean()
以ApplicationContext为例,流程是: ApplicationContext.getBean()----》BeanFactory.getBean()----》AbstractBeanFactory.getBean()
在这里插入图片描述
而真正做事情的是deGetBean方法

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {//获取beanNameString beanName = transformedBeanName(name);Object beanInstance;//无论是什么作用域都先尝试从单例池获取Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.trace("Returning cached instance of singleton bean '" + beanName + "'");}}//有时候并不是放回实例本身,而是返回其映射的实例。如:BeanFactory情况下返回指定方法返回的实例beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {//当原型模式下有循环依赖时,抛异常(原型模式下若存在循环依赖会导致内存泄漏)if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}//尝试从父beanFactory加载beanBeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {String nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {return (T) parentBeanFactory.getBean(nameToLookup, args);}else if (requiredType != null) {return parentBeanFactory.getBean(nameToLookup, requiredType);}else {return (T) parentBeanFactory.getBean(nameToLookup);}}//如果不是仅仅做类型检查则是创建bean,这里进行记录if (!typeCheckOnly) {markBeanAsCreated(beanName);}StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate").tag("beanName", name);try {if (requiredType != null) {beanCreation.tag("beanType", requiredType::toString);}//得到合并后的beanDefinitionRootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);//检查beanDefinition,抽象的beanDefinition会报错checkMergedBeanDefinition(mbd, beanName, args);//先加载dependsOn标注的beanString[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {//dePendsOn引起的循环依赖,抛异常if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//注册dependentBeanMap(dependsOn 于哪些bean)和注册dependenciesForBeanMap(被哪些bean dependOn)registerDependentBean(dep, beanName);try {getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}//-----------------------------------开始创建bean-----------------------------------------------//单例模式if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {destroySingleton(beanName);throw ex;}});beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}//原型模式else if (mbd.isPrototype()) {Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}//其他模式else {String scopeName = mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");}Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new ScopeNotActiveException(beanName, scopeName, ex);}}}catch (BeansException ex) {beanCreation.tag("exception", ex.getClass().toString());beanCreation.tag("message", String.valueOf(ex.getMessage()));cleanupAfterBeanCreationFailure(beanName);throw ex;}finally {beanCreation.end();}}//必要时进行类型转换return adaptBeanInstance(name, beanInstance, requiredType);}

bean的创建

从bean的加载中得知,当一个从缓存中获取不到的时候就会调用createBean方法去创建一个bean。而在AbstractBeanFactory中这是一个抽象方法,具体的创建逻辑由具体的beanFactory类自行实现。至少目前为止,spring内置的实现只有AbstractAutowireCapableBeanFactory.createBean()。无论是AnnotationConfigApplicationContext还是ClassPathXmlApplicationContext创建bean的逻辑最终都会来到这个方法。

虽然AnnotationConfigApplicationContext和ClassPathXmlApplicationContext并不直接继承AbstractAutowireCapableBeanFactory。但是都维护了一个DefaultListableBeanFactory成员变量,而这个成员变量继承自AbstractAutowireCapableBeanFactory。

createBean
在这里插入图片描述

doCreateBean

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {//如果是单例,factoryBeanCache.removeBeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}//实例化beanif (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}//MergedBeanDefinitionPostProcessor的应用(如:AutowiredAnnotationBeanPostProcessor)synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}//提前暴露bean,循环依赖处理boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}Object exposedObject = bean;try {//属性填充//填充属性之前会调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation//填充属性之后会调用 InstantiationAwareBeanPostProcessor.postProcessProperties --如果返回null--> postProcessPropertyValuespopulateBean(beanName, mbd, instanceWrapper);//初始化bean(是指据配置自定义的初始化bean如:@PostConstruct,而不是指构造方法的初始化)//初始化之前会调用 PostProcessors.postProcessBeforeInitialization//初始化之后会调用 PostProcessors.postProcessAfterInstantiationexposedObject = 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<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");}}}}//注册DisposableBean,如果配置了destroy-methoy,这里需要注册以便于在销毁的时候调用try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}

initializeBean
在这里插入图片描述


总结

getBean流程

1:transformedBeanName(name) 转换为对应的beanName
2:getSingleton(beanName) 尝试从缓存中加载单例
3:isPrototypeCurrentlyIncreation(beanName) 原型模式的依赖检查
4:检测父BeanFactory
5:getMergedLocalBeanDefinition(beanName) GernericBeanDefinition转换为RootBeanDefinition
6:依赖检测
7:根据不同的模式创建bean
8:getObjectForBeanInstance(prototypeInstance, name, beanName, mbd) 根据得到的Bean获取真正对象
9:如果需要则做类型转换

createBean流程

1:锁定class
2:指定方法的覆盖
3:InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
4:doCreateBean

doCreateBean流程

1:若为单例,移除factoryBeanCache内的缓存
2:实例化Bean
3:MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(如:AutowiredAnnotationBeanPostProcessor)
4:提前暴露bean,循环依赖处理

(populateBean)
5:InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
6:属性填充
7:InstantiationAwareBeanPostProcessor.postProcessProperties --如果返回null–> postProcessPropertyValues

(initializeBean)
8:aware方法的执行(beanNameAware,beanClassLoaderAware,beanFactoryAware)
9:PostProcessors.postProcessBeforeInitialization
10:自定义初始化bean(如:InitializingBean.afterPropertiesSet,@PostConstruct,init-method)
11:PostProcessors.postProcessAfterInstantiation

12:循环依赖检查,判断是否需要抛出异常
13:注册DisposableBean

相关文章:

spring源码篇(3)——bean的加载和创建

spring-framework 版本&#xff1a;v5.3.19 文章目录bean的加载bean的创建总结getBean流程createBean流程doCreateBean流程bean的加载 beanFactory的genBean最常用的一个实现就是AbstractBeanFactory.getBean()。 以ApplicationContext为例&#xff0c;流程是: ApplicationCon…...

Spring 中事务的传播级别

Spring 中事务的传播级别 REQUIRED(默认)&#xff1a;默认的隔离级别&#xff0c;如果当前存在一个事务&#xff0c;就加入该事务&#xff0c;如果当前没有事务&#xff0c;就创建一个新的事务。 REQUIRED_NEW&#xff1a;不管当前是否存在事务&#xff0c;都创建一个新的事物…...

ECharts可视化库--常用组件

目录 一.series系列 二.常见组件 1.标题title 2.图例legend 3.工具栏toolbox 4.提示框tooltip 5.坐标轴 xAxis yAsix 6.series系列 上一篇已经介绍了ECharts库的导入工作和绘制基本的图标&#xff0c;今天我们来了解一下常用的组件&#xff0c;如果对数据可视化感兴…...

openpnp - 设备开机后, 吸嘴校验失败的解决方法

文章目录openpnp - 设备开机后, 吸嘴校验失败的解决方法概述重新校验吸嘴ENDopenpnp - 设备开机后, 吸嘴校验失败的解决方法 概述 设备开机后, 默认会校验吸嘴座上已经安装的2个吸嘴. 如果开机校验吸嘴失败, 就需要用向导重新校验失败的吸嘴. 具体是哪个吸嘴校验失败, 可以看…...

【Linux学习】基础IO——软硬链接 | 制作动静态库

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 基础IO&#x1f353;软硬链接&#x1f332;软链接&#x1f332;硬链接&#x1f353;动静态库&…...

如何分辨on-policy和off-policy

on-policy的定义&#xff1a;behavior policy和target-policy相同的是on-policy&#xff0c;不同的是off-policy。 behavior policy&#xff1a;采样数据的策略&#xff0c;影响的是采样出来s,a的分布。 target policy&#xff1a;就是被不断迭代修改的策略。 如果是基于深度…...

第三讲:ambari编译后的安装包制作流程说明

一、概述 前两讲,我们已经将 Ambari 源码编译成功。现在我们想将 Ambari 编译后的 rpm 包,都放到 yum 本地仓库中,这样 Ambari 与 HDP 在安装部署时,就直接使用的我们自己编译的安装包了。 Ambari 的 rpm 包,有这么几类: ambari-server rpmambari-agent rpmambari metr…...

Python进阶-----面对对象6.0(绑定方法[类方法、静态方法]与内置方法)

目录 前言&#xff1a; 1.绑定方法 &#xff08;1&#xff09;实例方法 &#xff08;2&#xff09;类方法 &#xff08;3&#xff09;静态方法 2.类型检测 &#xff08;1&#xff09;issubclass() 函数 &#xff08;2&#xff09;isinstance() 函数 3.内置方法&#xf…...

java8四大基本函数式接口

1.什么是函数式接口? 只包含一个抽象方法的接口&#xff0c;称为函数式接口你可以通过Lambda表达式来创建该接口的对象。&#xff08;若Lambda表达式抛出一个受检异常&#xff0c;那么该异常需要在目标接口的抽象方法上进行声明&#xff09;我们可以在任意函数式接口上使用Fu…...

Junit测试框架

一、简介 Junit框架是一个开源的Java语言单元测试框架&#xff0c;Java方向使用最广泛的单元测试框架&#xff0c;使用Java开发者都应该学习Junit并能掌握单元测试的编写。 对于Junit和Selenium的关系&#xff1a;通俗点来说Selenium如果比喻为灯泡&#xff0c;那么Junit就是电…...

操作系统复习题

什么是线程&#xff1f; 线程&#xff08;Thread&#xff09;&#xff1a;轻量级进程&#xff0c;是操作系统进行调度的最小单位。一个线程是一个任务&#xff08;一个程序段&#xff09;的一次执行过程。线程不占有内存空间&#xff0c;它包括在进程的内存空间中。在同一个进程…...

web项目的初始化

Tomcat 安装配置 Tomcat 官方站点&#xff1a;Apache Tomcat - Welcome! 。 安装 得到下载的安装包&#xff08;一般是 zip 文件&#xff09;&#xff0c;并解压到你指定的目录&#xff08;建议不要解压在 c 盘&#xff09;&#xff1b;&#xff08;这里以 windows10 系统为例…...

29- 迁移学习 (TensorFlow系列) (深度学习)

知识要点 迁移学习: 使用别人预训练模型参数时&#xff0c;要注意别人的预处理方式。 常见的迁移学习方式&#xff1a; 载入权重后训练所有参数.载入权重后只训练最后几层参数.载入权重后在原网络基础上再添加一层全连接层&#xff0c;仅训练最后一个全连接层.训练数据是 10_m…...

工具篇(五)炫酷排版,尽在LaTeX:让你的文档飞升吧!

作者的话 作为一个文本排版工具&#xff0c;latex一直以来都备受科研工作者、学生和出版社的青睐。但是对于初学者来说&#xff0c;latex的学习曲线可能会有些陡峭。因此&#xff0c;我写这篇博客旨在为初学者提供一个简单易懂的latex教程&#xff0c;让大家能够快速入门并掌握…...

【蓝桥杯PythonB组备赛】【Acwing周赛】第93场 4867. 整除数 4868. 数字替换 python解

目录 A AcWing 4867. 整除数 1.题目描述 2.思路分析 3.代码实现 B AcWing 4868. 数字替换 1.题目描述 2.思路分析 3.代码实现 A AcWing 4867. 整除数 1.题目描述 2.思路分析 为什么不能直接暴力&#xff1f; 数据&#xff1a;1 ≤ n, k ≤ 10 ** 9 1s内最多…...

KNN学习报告

原理 KNN算法就是在其表征空间中&#xff0c;求K个最邻近的点。根据已知的这几个点对其进行分类。如果其特征参数只有一个&#xff0c;那么就是一维空间。如果其特征参数只有两个&#xff0c;那么就是二维空间。如果其特征参数只有三个&#xff0c;那么就是三维空间。如果其特征…...

Java奠基】方法的讲解与使用

目录 方法概述 方法的定义与调用 方法的重载 方法的值传递 方法概述 方法是程序中最小的执行单元&#xff0c;在实际开发中会将重复的具有独立功能的代码抽取到方法中&#xff0c;这样可以提高代码的复用性和可维护性。 方法的定义与调用 在Java中定义方法的格式都是相同…...

字符串hash

K - 子串翻转回文串2020ccpc河南省赛字符串哈希&#xff1a;将字符串变成x进制数对公式的理解&#xff1a;举个十进制数的例子&#xff1a;123456h[1]1&#xff1b;h[2]1*10212;h[3]12*103123;h[4]123*1041234;.........h[i]h[i-1]*xa[i];h[i]代表的恰巧是整个数的前缀用p[i]表…...

试题 算法训练 转圈游戏

问题描述 n个小伙伴&#xff08;编号从0到n-1&#xff09;围坐一圈玩游戏。按照顺时针方向给n个位置编号&#xff0c;从0到n-1。   最初&#xff0c;第0号小伙伴在第0号位置&#xff0c;第1号小伙伴在第 1 号位置&#xff0c;……&#xff0c;依此类推。   游戏规则如下&am…...

【uni-app教程】九、运行环境判断与跨端兼容

&#xff08;1&#xff09;开发环境和生产环境 uni-app 可通过 process.env.NODE_ENV 判断当前环境是开发环境还是生产环境&#xff0c;一般用于连接测试服务器或生产服务器的动态切换。 在HBuilderX 中&#xff0c;点击「运行」编译出来的代码是开发环境&#xff0c;点击「发行…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制

目录 节点的功能承载层&#xff08;GATT/Adv&#xff09;局限性&#xff1a; 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能&#xff0c;如 Configuration …...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...