(Spring学习07)Spring之推断构造方法源码解析

基本流程

推断构造方法流程图:
https://www.processon.com/view/link/5f97bc717d9c0806f291d7eb

AutowiredAnnotationBeanPostProcessor中推断构造方法不同情况思维脑图:https://www.processon.com/view/link/6146def57d9c08198c58bb26

Spring中的一个bean,需要实例化得到一个对象,而实例化就需要用到构造方法。

一般情况下,一个类只有一个构造方法:要么是无参的构造方法,要么是有参的构造方法

如果只有一个无参的构造方法,那么实例化就只能使用这个构造方法了。
如果只有一个有参的构造方法,那么实例化时能使用这个构造方法吗?要分情况讨论:

  1. 使用AnnotationConfigApplicationContext,会使用这个构造方法进行实例化,那么Spring会根据构造方法的参数信息去寻找bean,然后传给构造方法
  2. 使用ClassPathXmlApplicationContext,表示使用XML的方式来使用bean,要么在XML中指定构造方法的参数值(手动指定),要么配置autowire=constructor让Spring自动去寻找bean做为构造方法参数值。
    .

上面是只有一个构造方法的情况,那么如果有多个构造方法呢?
又分为两种情况,多个构造方法中存不存在无参的构造方法。
分析:一个类存在多个构造方法,那么Spring进行实例化之前,该如何去确定到底用哪个构造方法呢?

  1. 如果开发者指定了想要使用的构造方法,那么就用这个构造方法
  2. 如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构造方法
  3. 如果开发者也没有让Spring自动去选择构造方法,则Spring利用无参构造方法,如果没有无参构造方法,则报错

针对第一点,开发者可以通过什么方式来指定使用哪个构造方法呢?

  1. xml中的标签,这个标签表示构造方法参数,所以可以根据这个确定想要使用的构造方法的参数个数,从而确定想要使用的构造方法
  2. 通过@Autowired注解,@Autowired注解可以写在构造方法上,所以哪个构造方法上写了@Autowired注解,表示开发者想使用哪个构造方法,当然,它和第一个方式的不同点是,通过xml的方式,我们直接指定了构造方法的参数值,而通过@Autowired注解的方式,需要Spring通过byType+byName的方式去找到符合条件的bean作为构造方法的参数值

再来看第二点,如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构造方法,对于这一点,只能用在ClassPathXmlApplicationContext,因为通过AnnotationConfigApplicationContext没有办法去指定某个bean可以自动去选择构造方法,而通过ClassPathXmlApplicationContext可以在xml中指定某个bean的autowire为constructor,虽然这个属性表示通过构造方法自动注入,所以需要自动的去选择一个构造方法进行自动注入,因为是构造方法,所以顺便是进行实例化。

当然,还有一种情况,就是多个构造方法上写了@Autowired注解,那么此时Spring会报错。
但是,因为@Autowired还有一个属性required,默认为ture,所以一个类中,只有能一个构造方法标注了@Autowired或@Autowired(required=true),有多个会报错。但是可以有多个@Autowired(required=false),这种情况下,需要Spring从这些构造方法中去自动选择一个构造方法。

源码思路

  1. AbstractAutowireCapableBeanFactory类中的createBeanInstance()方法会去创建一个Bean实例
  2. 根据BeanDefinition加载类得到Class对象
  3. 如果BeanDefinition绑定了一个Supplier,那就调用Supplier的get方法得到一个对象并直接返回
  4. 如果BeanDefinition中存在factoryMethodName,那么就调用该工厂方法得到一个bean对象并返回
  5. 如果BeanDefinition已经自动构造过了,那就调用autowireConstructor()自动构造一个对象
  6. 调用SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors()方法得到哪些构造方法是可以用的
  7. 如果存在可用得构造方法,或者当前BeanDefinition的autowired是AUTOWIRE_CONSTRUCTOR,或者BeanDefinition中指定了构造方法参数值,或者创建Bean的时候指定了构造方法参数值,那么就调用**autowireConstructor()**方法自动构造一个对象
  8. 最后,如果不是上述情况,就根据无参的构造方法实例化一个对象

autowireConstructor()

  1. 先检查是否指定了具体的构造方法和构造方法参数值,或者在BeanDefinition中缓存了具体的构造方法或构造方法参数值,如果存在那么则直接使用该构造方法进行实例化
  2. 如果没有确定的构造方法或构造方法参数值,那么
    i. 如果没有确定的构造方法,那么则找出类中所有的构造方法
    ii. 如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化
    iii. 如果有多个可用的构造方法或者当前Bean需要自动通过构造方法注入
    iv. 根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数
    v. 对所有的构造方法进行排序,参数个数多的在前面
    vi. 遍历每个构造方法
    vii. 如果不是调用getBean方法时所指定的构造方法参数值,那么则根据构造方法参数类型找值
    viii. 如果时调用getBean方法时所指定的构造方法参数值,就直接利用这些值
    ix. 如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的

为什么分越少优先级越高?

主要是计算找到的bean和构造方法参数类型匹配程度有多高。

假设bean的类型为A,A的父类是B,B的父类是C,同时A实现了接口D
如果构造方法的参数类型为A,那么完全匹配,得分为0
如果构造方法的参数类型为B,那么得分为2
如果构造方法的参数类型为C,那么得分为4
如果构造方法的参数类型为D,那么得分为1

可以直接使用如下代码进行测试:

Object[] objects = new Object[]{new A()};

// 0
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{A.class}, objects));

// 2
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{B.class}, objects));

// 4
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{C.class}, objects));

// 1
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{D.class}, objects));

所以,我们可以发现,越匹配分数越低。

@Bean的情况

首先,Spring会把@Bean修饰的方法解析成BeanDefinition:

  1. 如果方法是static的,那么解析出来的BeanDefinition中:
    i. factoryBeanName为AppConfig所对应的beanName,比如"appConfig"
    ii. factoryMethodName为对应的方法名,比如"aService"
    iii. factoryClass为AppConfig.class
  2. 如果方法不是static的,那么解析出来的BeanDefinition中:
    i. factoryBeanName为null
    ii. factoryMethodName为对应的方法名,比如"aService"
    iii. factoryClass也为AppConfig.class
    在由@Bean生成的BeanDefinition中,有一个重要的属性isFactoryMethodUnique,表示factoryMethod是不是唯一的,在普通情况下@Bean生成的BeanDefinition的isFactoryMethodUnique为true,但是如果出现了方法重载,那么就是特殊的情况,比如:
 @Bean
 public static AService aService(){
  return new AService();
 }

 @Bean
 public AService aService(BService bService){
  return new AService();
 }

虽然有两个@Bean,但是肯定只会生成一个aService的Bean,那么Spring在处理@Bean时,也只会生成一个aService的BeanDefinition,比如Spring先解析到第一个@Bean,会生成一个BeanDefinition,此时isFactoryMethodUnique为true,但是解析到第二个@Bean时,会判断出来beanDefinitionMap中已经存在一个aService的BeanDefinition了,那么会把之前的这个BeanDefinition的isFactoryMethodUnique修改为false,并且不会生成新的BeanDefinition了。

并且后续在根据BeanDefinition创建Bean时,会根据isFactoryMethodUnique来操作,如果为true,那就表示当前BeanDefinition只对应了一个方法,那也就是只能用这个方法来创建Bean了,但是如果isFactoryMethodUnique为false,那就表示当前BeanDefition对应了多个方法,需要和推断构造方法的逻辑一样,去选择用哪个方法来创建Bean。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/201759.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

stm32 计数模式

计数模式 但是对于通用定时器而言,计数器的计数模式不止向上计数这一种。上文基本定时器中计数器的计数模式都是向上计数的模式。 向上计数模式:计数器从0开始,向上自增,计到和自动重装寄存器的目标值相等时,计数器清…

安卓apk抓包

起因 手机(模拟器)有时候抓不到apk的包,需要借助Postern设置一个代理,把模拟器的流量代理到物理机的burp上。 解决方案 使用Postern代理,把apk的流量代理到burp。 Postern是一个用于代理和网络流量路由的工具&#xf…

Apache Flink(三):Flink核心特性及应用场景

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹…

Linux服务器SSH客户端断开后保持程序继续运行的方法

目录 1. nohup 命令: 2. tmux 或 screen: 3 final shell 断开后服务器如何继续执行令? 方法一:使用 nohup 命令 方法二:将命令放在后台执行 4 你可以使用 jobs 命令查看当前终端中正在后台运行的任务 &#xff…

【Linux | Docker】内网穿透实现远程访问Nginx Proxy Manager

文章目录 前言1. docker 一键安装2. 本地访问3. Linux 安装cpolar4. 配置公网访问地址5. 公网远程访问6. 固定公网地址 前言 Nginx Proxy Manager 是一个开源的反向代理工具,不需要了解太多 Nginx 或 Letsencrypt 的相关知识,即可快速将你的服务暴露到外…

C++设计模式——原型 (克隆)模式

一、什么是原型模式 Prototype模式说简单点,就是提供了一个clone, 通过已存在对象进行新对象创建。clone()实现和具体的实现语言相关,在C中我们通过拷贝构造函数实现。 那为啥要写clone的接口来实现这个目的呢?直接使…

关于2024年天津铁道职业技术学院专升本考试报名工作的通知

天津铁道职业技术学院关于2024年高职升本科报名工作的通知 根据市高招办关于2024年天津市高职升本科的工作安排,为做好天津铁道职业技术学院2024届毕业生高职升本科考试报名工作,现将相关事项通知如下: 1. 报考资格:2024届天津铁…

【EI会议征稿】第四届生物信息学与智能计算国际学术研讨会(BIC 2024)

第四届生物信息学与智能计算国际学术研讨会(BIC 2024) 2024 4th International Conference on Bioinformatics and Intelligent Computing 2024年第四届生物信息学与智能计算国际学术研讨会 (BIC 2024)将定于2024年1月26-28日在…

ora.LISTENER.lsnr状态为Not All Endpoints Registered

客户的监控反馈有个监听无法连接,登录环境检查发现ora.LISTENER.lsnr的状态为Not All Endpoints Registered,如下 [rootdb2 ~]# crsctl status res -t -------------------------------------------------------------------------------- NAME …

IDEA如何配置Git 遇到问题的解决

新建项目 点击 会变红 会生成.git隐藏文件 配置远程仓库路径:点击Manage Remotes:将远程仓库的链接放到这里: 得到如下样式: 此时提交到本地仓库 点击add,添加到暂存文件: 此时文件变绿&#xf…

5 面试题--redis

伪客户端: 伪客户端的 fd 属性值为 -1;伪客户端处理的命令请求来源于 AOF ⽂件或者 Lua 脚本,⽽不是⽹络,所以这种客户端不需要套接字连接,⾃然也不需要记录套接字描述符。⽬前 Redis 服务器会在两个地⽅ ⽤到伪客户端…

【Web】NewStarCTF Week3 个人复现

①Include &#x1f350; ?filephpinfo 提示查下register_argc_argv 发现为on LFI包含 pearcmd命令执行学习 pearcmd.php文件包含妙用 ?file/usr/local/lib/php/pearcmd&config-create/<?eval($_POST[a])?>./ha.php ?file./ha post传&#xff1a; asystem…

云时空社会化商业 ERP 系统 service SQL 注入漏洞复现

0x01 产品简介 时空云社会化商业ERP&#xff08;简称时空云ERP&#xff09; &#xff0c;该产品采用JAVA语言和Oracle数据库&#xff0c; 融合用友软件的先进管理理念&#xff0c;汇集各医药企业特色管理需求&#xff0c;通过规范各个流通环节从而提高企业竞争力、降低人员成本…

关于MongoDB

MongoDB介绍 MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据库的。它支持的数据结构非常松散&#xff0c;因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大&#xff0c;其…

【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能

文章目录 ⭐⭐⭐Spring核心源码分析自定义Spring框架⭐⭐⭐一、Spring使用回顾二、Spring核心功能结构1、Spring核心功能2、bean概述 三、Spring IOC相关接口分析1、BeanFactory解析2、BeanDefinition解析3、BeanDefinitionReader解析4、BeanDefinitionRegistry解析5、创建容器…

科研学习|论文解读——Task complexity and difficulty in music information retrieval

摘要&#xff1a; 关于音乐信息检索&#xff08;MIR&#xff09;中任务复杂度和任务难度的研究很少&#xff0c;而文本检索领域的许多研究发现任务复杂度和任务难度对用户效率有显着影响。本研究旨在通过探索 i) 任务复杂度和任务难度之间的关系&#xff1b; ii) 影响任务难度的…

基于合成数据的行人检测AI模型训练

在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 近年来&#xff0c;自动驾驶汽车因其对社会的广泛影响而越来越受欢迎&#xff0c;因为它们提高…

专业的事交给专业的公司来做,文件销毁 数据销毁 硬盘销毁

在当今信息化社会&#xff0c;数据和文件已经成为企业和个人生活中不可或缺的一部分。然而&#xff0c;随着数据量的不断增长&#xff0c;如何确保数据的安全性和隐私性成为了一个亟待解决的问题。为了解决这个问题&#xff0c;文件销毁、硬盘销毁、数据销毁和物料销毁等技术应…

作为用户,推荐算法真的是最优解么?

前言 众所周知&#xff0c;随着互联网技术的发展&#xff0c;推荐算法也越来越普及。无论是购物网站、社交媒体平台还是在线影视平台&#xff0c;推荐算法已成为用户获取相关信息的主要途径。据悉&#xff0c;近期GitHub决定结合算法推荐&#xff0c;将“Following”和“For Yo…

利用ogr2ogr从PostGIS中导出/导入Tab/Dxf/Geojson等格式数据

ogr2ogr Demo Command 先查看下当前gdal支持的全部格式&#xff0c;部分gdal版本可能不支持PostGIS。 如出现PostgreSQL表名支持。 #全部支持的格式 ogrinfo --formats | sort #AVCBin -vector- (rov): Arc/Info Binary Coverage #AVCE00 -vector- (rov): Arc/Info E00 (ASC…