【Spring源码】createBeanInstance()

2023-11-17

位置

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   
		// 实例化bean
        BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
        // 属性填充
        populateBean(beanName, mbd, instanceWrapper);
        // 调用初始化方法
        return initializeBean(beanName, instanceWrapper.getWrappedInstance(), mbd);
    }

创建实例-createBeanInstance

    /**
     * 使用适当的实例化策略为指定的 bean 创建一个新实例:
     * 工厂方法、构造函数自动装配或简单实例化。
     * @param beanName bean 的名称
     * @param mbd bean 的 bean 定义
     * @param args 用于构造函数或工厂方法调用的显式参数
     * @return 新实例的 BeanWrapper
     * @see #obtainFromSupplier
     * @see #instantiateUsingFactoryMethod
     * @see #autowireConstructor
     * @see #instantiateBean
     */
    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   
        // 确保此时真正解析了 bean 类。
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        // 校验这个instanceSupplier是否有值,有的话,调用这个字段获取对象。
		// 工厂方法创建对象使用反射调用目标方法,不如直接调用目标方法效率高
        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
   
            return obtainFromSupplier(instanceSupplier, beanName);
        }
        // 如果工厂方法不为空则使用工厂方法初始化策略
        if (mbd.getFactoryMethodName() != null) {
   
            // 1、RootBeanDefinition 中存在 factoryMethodName属性,或配置文件中配置了factory-method,根据配置生成实例
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // 重新创建同一个 bean 时的快捷方式...
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
   
            synchronized (mbd.constructorArgumentLock) {
   
                // 2、判断过程很耗性能,采用缓存机制,RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod缓存中去取
                // 根据参数及类型锁定对应的构造函数或工厂方法
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
   
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        // 如果已经解析过则使用解析好的构造函数不需要再次锁定
        if (resolved) {
   
            if (autowireNecessary) {
   
                // 构造函数自动注入
                return autowireConstructor(beanName, mbd, null, null);
            } else {
   
                // 默认构造函数构造
                return instantiateBean(beanName, mbd);
            }
        }

        // 根据参数解析构造函数
        // 自动装配的候选构造函数?
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
   
            // 构造函数自动注入
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // 没有特殊处理:只需使用无参数构造函数。
        return instantiateBean(beanName, mbd);
    }
有参构造-autowireConstructor
1、构造函数参数的确定
	1)根据explicitArgs参数判断
	2)缓存中获取
	3)配置文件获取
2、构造函数的确定
3、根据确定的构造函数转换对应的参数类型
4、构造函数不确定性的验证
	因为不同构造函数的参数为父子关系
5、根据实例化策略以及得到的构造函数及其参数实例化Bean
    /**
     * “自动装配构造函数”(按类型使用构造函数参数)行为。
     * 如果指定了显式构造函数参数值,也适用,将所有剩余参数与来自 bean 工厂的 bean 匹配。
     * 这对应于构造函数注入:在这种模式下,Spring bean 工厂能够承载期望基于构造函数的依赖项解析的组件。
     * @param beanName bean 的名称
     * @param mbd bean 的 bean 定义
     * @param chosenCtors 选择的候选构造函数
     * @param explicitArgs 参数值通过 getBean 方法以编程方式传入,或者 {@code null} 如果没有(-> 使用 bean 定义中的构造函数参数值)
     * @return 新实例的 BeanWrapper
     */
    public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
                                           @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
   

        BeanWrapperImpl bw = new BeanWrapperImpl();
        this.beanFactory.initBeanWrapper(bw);

        Constructor<?> constructorToUse = null;
        ArgumentsHolder argsHolderToUse = null;
        Object[] argsToUse = null;

        // explicitArgs 通过getBean()传入
        if (explicitArgs != null) {
   
            // 如果 getBean() 调用的时候指定方法参数那么直接使用
            argsToUse = explicitArgs;
        } else {
   
            // 如果 getBean() 调用的时候没有指定方法参数,则尝试从配置文件中解析
            Object[] argsToResolve = null;
            // 尝试从缓存中获取
            synchronized (mbd.constructorArgumentLock) {
   
                constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
                if (constructorToUse != null && mbd.constructorArgumentsResolved) {
   
                    // 从缓存中取
                    // 找到一个缓存的构造函数...
                    argsToUse = mbd.resolvedConstructorArguments;
                    if (argsToUse == null) {
   
                        // 配置的构造函数参数
                        argsToResolve = mbd.preparedConstructorArguments;
                    }
                }
            }
            // 如果缓存中存在
            if (argsToResolve != null) {
   
                // 解析参数类型,如给定方法的构造函数A(int,int)通过此方法后就会把配置中的("1","1")转换为(1,1)
                // 缓存中的值可能是原始值或者最终值
                argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
            }
        }
        // 没有被缓存
        if (constructorToUse == null) {
   
            // 需要解析构造函数.
            boolean autowiring = (chosenCtors != null ||
                    mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
            ConstructorArgumentValues resolvedValues = null;

            int minNrOfArgs;
            if (explicitArgs != null) {
   
                minNrOfArgs = explicitArgs.length;
            } else {
   
                // 提取配置文件中的配置的构造函数参数
                ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                // 用于承载解析后的构造函数参数的值
                resolvedValues = new ConstructorArgumentValues();
                // 能解析到的参数个数
                minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
            }

            // 使用指定的构造函数,如果有的话。
            Constructor<?>[] candidates = chosenCtors;
            if (candidates == null) {
   
                Class<?> beanClass = mbd.getBeanClass();
                candidates = (mbd.isNonPublicAccessAllowed() ?
                   beanClass.getDeclaredConstructors() : beanClass.getConstructors());
            }
            // 排序给定的构造函数,public构造函数优先参数数量降序、非public构造函数参数数量降序
            AutowireUtils.sortConstructors(candidates);
            int minTypeDiffWeight = Integer.MAX_VALUE;
            Set<Constructor<?>> ambiguousConstructors = null;
            LinkedList<UnsatisfiedDependencyException> causes =
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Spring源码】createBeanInstance() 的相关文章

随机推荐

  • 最能感动女人的十大瞬间

    拉着手在街上闲逛 忽然之间 他将她拽停 伸手轻轻地将眼睑下的一根睫毛拨开 她顿感幸福 拨走睫毛不过是弹指之间的小事 却充分说明他对她的注意力100 集中 要不是他喜欢仔细地偷看她 怎能发现刚跌落的一根细小睫毛 没有一个女人 能够抵抗男人如此
  • Java爬虫框架WebMagic的使用总结

    最近 项目做一个公司新闻网站 分为PC 移动端 h5 数据来源是从HSZX与huanqiu2个网站爬取 主要使用Java编写的WebMagic作为爬虫框架 数据分为批量抓取 增量抓取 批量抓当前所有历史数据 增量需要每10分钟定时抓取一次
  • CSS3 弹性盒子(flex、flex-direction属性、flex-wrap属性、align-items属性、align-content属性)详解

    文章目录 flex flex direction 属性 flex wrap 属性 align items 属性 align content 属性的使用 flex 在 CSS3 中给 display 属性增加了新的属性值 flex 如果一个元
  • 关于MFC中使用ShellExecute出现的进程冲突问题

    目录 问题背景 问题分析 问题背景 现在有一个MFC写的界面程序 以及一个外部exe文件 用户通过界面选择文件a MFC将文件a的路径作为参数 调用exe文件生成一个解析文件b 然后MFC再读取这个文件b 为了完成这一目的 就需要在MFC中
  • Airtest IDE 使用方法

    1 assert exists 找到图片则返回图片坐标 否则报错 raise AssertionError 引发断言错误 2 assert not exists 没找到图片则返回None 否则报错 raise AssertionError
  • 项目实战——文档扫描OCR识别

    扫描全能王的实现 maybe 目录 一 文档扫描 1 引入所需要的库 2 图像的读取与预处理 读取图像 图像reszie 图像灰度化 滤波 边缘检测 3 轮廓检测 4 透视与二值变换 二 文字识别 一 文档扫描 文档扫描所实现的功能如下图所
  • 【转载】浅谈蓝牙 Mesh 组网技术

    本文转载自 Eren https www erenship com posts 63c7 html 蓝牙技术联盟官方网址 https www bluetooth com zh cn 蓝牙技术联盟公众号 BluetoothSIG 蓝牙技术联盟
  • BIO与NIO、AIO的区别

    IO的方式通常分为几种 同步阻塞的BIO 同步非阻塞的NIO 异步非阻塞的AIO 一 BIO 在JDK1 4出来之前 我们建立网络连接的时候采用BIO模式 需要先在服务端启动一个ServerSocket 然后在客户端启动Socket来对服务
  • 使用Nuget 安装指定版本package或者更新package到指定版本

    首先打开程序包管理器控制台 工具 Nuget程序包管理器 程序包管理器控制台 打开如下图所示的命令行界面 安装指定版本的Package 例如 EntityFramework 5 0 PM gt Install Package BenchMa
  • 关于yolov5训练大量数据存在的问题记录

    相关配置环境 拉取官方最新的镜像 docker pull ultralytics yolov5 以及代码 git clone https github com ultralytics yolov5 torch 1 10 1 cu102 CU
  • 小程序requiredPrivateInfos 无效以及闪退问题

    原生微信小程序踩坑 requiredPrivateInfos 无效 1 检查单词拼写是否正确以及是否有空格存在 2 检查是否在微信公众平台中申请了权限 3 将多行改为一行 requiredPrivateInfos xxxxxxx xxxx
  • 【Qt】实现在窗口缩放时控件维持相对位置

    文章目录 01 背景 02 解决方案 03 位置和大小的计算 03 1 控件宽度或高度始终与窗体一致 03 2 控件左右居中 03 3 控件上下居中 03 4 控件位于窗体右上角 03 5 控件位于左右居中线向右30像素的地方 04 完成效
  • 华为od机试 Java 【编码方式】

    题目 你需要创建一个特殊的整数编码程序 在这个程序中 数字较小时 它的编码占用的空间也应更小 你的任务是根据以下规则将一个整数转换为一个特殊的编码字符串 将整数转换为它的二进制形式 从右到左每7位组成一个编码单元 在每个编码单元的前面添加一
  • C语言指针(一)——什么是指针及指针的定义

    1 什么是指针 计算机中所有的数据都必须放在内存中 不同类型的数据占用的字节数不一样 例如int 占用4个字节 char占用1个字节 为了正确地访问这些数据 必须为每个字节都编上号码 就像门牌号一样 每个字节的编号是唯一的 根据编号可以准确
  • 他98年的,我玩不过他...

    现在的小年轻真的卷得过分了 前段时间我们公司来了个98年的 工作没两年 跳槽到我们公司起薪18K 都快接近我了 后来才知道人家是个卷王 从早干到晚就差搬张床到工位睡觉了 最近和他聊了一次天 原来这位小老弟家里条件不太好 一大家子指望他一个人
  • Java 责任链模式

    责任链模式 一 什么是责任链模式 二 责任链模式的优势和劣势 2 1 优势 2 2 劣势 三 示例 一 什么是责任链模式 责任链模式定义 为了避免请求发送者与多个请求处理者耦合在一起 于是将所有请求的处理者通过前一对象记住其下一个对象的引用
  • YOLOv5+deepsort实现目标追踪。(附有各种错误解决办法)

    一 YOLOv5算法相关配置 这里如果是自己只想跑一跑YOLOV5的话 可以参考本章节 只想跑通YOLOv5 deepsort的看官移步到下一章节 1 1 yolov5下载 yolov5源码在github下载地址上或者Gitee上面都有 需
  • Critical dependency: the request of a dependency is an expression(import)

    定位到vue文件问题所在位置 export default created 告警所在 import md file then moduleFile gt catch err gt 原因 webpack 版本问题 webpack4中动态imp
  • 小程序中轮播图u-swiper图片无法显示问题

    问题 uview官网中 指定的图片路径字段为image 完全按照uview写轮播图却无法正常显示 解决方法 1 把image字段改成url字段 2 给u swiper加上 keyName image 最后找到了总结原因 npm下载的uvie
  • 【Spring源码】createBeanInstance()

    目录 创建实例 createBeanInstance 有参构造 autowireConstructor 无参构造 instantiateBean 实例化策略 instantiate createBeanInstance英文版 autowir