7 推断构造方法

推断构造方法

Spring中的一个bean,需要实例化得到一个对象,而实例化就需要用到构造方法。
一般情况下,一个类只有一个构造方法:
1. 要么是无参的构造方法
2. 要么是有参的构造方法
如果只有一个无参的构造方法,那么实例化就只能使用这个构造方法了。 如果只有一个有参的构造方
法,那么实例化时能使用这个构造方法吗?要分情况讨论:
1. 使用AnnotationConfigApplicationContext,会使用这个构造方法进行实例化,那么Spring会
根据构造方法的参数信息去寻找bean,然后传给构造方法
2. 使用ClassPathXmlApplicationContext,表示使用XML的方式来使用bean,要么在XML中指定
构造方法的参数值(手动指定),要么配置autowire=constructor让Spring自动去寻找bean做为
构造方法参数值。
上面是只有一个构造方法的情况,那么如果有多个构造方法呢?
又分为两种情况,多个构造方法中存不存在无参的构造方法。
分析:一个类存在多个构造方法,那么Spring进行实例化之前,该如何去确定到底用哪个构造方法
呢?
1. 如果开发者指定了想要使用的构造方法,那么就用这个构造方法
2. 如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构造方法
3. 如果开发者也没有让Spring自动去选择构造方法,则Spring利用无参构造方法,如果没有无参构
造方法,则报错
针对第一点,开发者可以通过什么方式来指定使用哪个构造方法呢?
1. xml中的<constructor-arg>标签,这个标签表示构造方法参数,所以可以根据这个确定想要使
用的构造方法的参数个数,从而确定想要使用的构造方法
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.mzph.cn/news/144575.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

验证码:EasyDL 机器学习识别与云码平台一站式识别

目录 EasyDL 机器学习识别&#xff08;实践&#xff1a;京东商城&#xff09; &#xff08;一&#xff09;批量获取验证码图片 &#xff08;二&#xff09;EasyDL机器学习&#xff08;百度智能云&#xff09; &#xff08;三&#xff09;调用EasyDLAPI接口识别验证码 云码…

bclinux aarch64 ceph 14.2.10 对象存储 http网关 CEPH OBJECT GATEWAY Civetweb

相关内容 bclinux aarch64 ceph 14.2.10 文件存储 Ceph File System, 需要部署mds&#xff1a; ceph-deploy mds-CSDN博客 ceph-deploy bclinux aarch64 ceph 14.2.10【3】vdbench fsd 文件系统测试-CSDN博客 ceph-deploy bclinux aarch64 ceph 14.2.10【2】vdbench rbd 块设…

unity shaderGraph实例-扫描效果

文章目录 效果展示整体结构各区域内容区域1区域2区域3区域4区域5区域6GraphSetttings注意事项使用方法 效果展示 整体结构 各区域内容 区域1 用场景深度减去顶点的View空间的视野深度&#xff08;Z值&#xff09;&#xff0c;这里Z值需要乘-1是因为从相机看到的物体顶点的视野…

大模型的实践应用6-百度文心一言的基础模型ERNIE的详细介绍,与BERT模型的比较说明

大家好,我是微学AI,今天给大家讲一下大模型的实践应用6-百度文心一言的基础模型ERNIE的详细介绍,与BERT模型的比较说明。在大规模语料库上预先训练的BERT等神经语言表示模型可以很好地从纯文本中捕获丰富的语义模式,并通过微调的方式一致地提高各种NLP任务的性能。然而,现…

JPA与sboot整合

JPA (Java Persistence API) 是一种标准化的 Java ORM (Object Relational Mapping) 框架&#xff0c;用于将 Java 对象映射到关系型数据库中的表结构。它提供了一种面向对象的思维方式来处理数据存储和检索&#xff0c;使得开发人员能够更加方便地对数据库进行操作。 JPA 的主…

el-select组件绑定change怎么获取label和value值

组件中change回调只能获取到value,但是有时候需求是要传两个参数&#xff08;elementui 封装的change只能获取到value,我们可以通过原生事件去获取option值&#xff09;。 如果要在element组件上触发原生事件&#xff0c;一律都得加.native修饰符&#xff0c;否则无法触发事件。…

【论文精读】Pose-Free Neural Radiance Fields via Implicit Pose Regularization

今天读的是一篇发表在ICCV 2023上的文章&#xff0c;作者来自NTU。 文章地址&#xff1a;点击前往 文章目录 Abstract1 Intro2 Related Work3 Preliminary4 Proposed Method4.1 Overall Framework4.2 Scene Codebook Construction4.3 Pose-Guided View Reconstruction4.4 Train…

spring中的DI

【知识要点】 控制反转&#xff08;IOC&#xff09;将对象的创建权限交给第三方模块完成&#xff0c;第三方模块需要将创建好的对象&#xff0c;以某种合适的方式交给引用对象去使用&#xff0c;这个过程称为依赖注入&#xff08;DI&#xff09;。如&#xff1a;A对象如果需要…

golang 上传图片 --chatGPT

问&#xff1a;makeImgUpload(path string) 实现发送发送图片&#xff0c; 发送类型为 multipart/form-data gpt: 下面是一个简单的 makeImgUpload 函数的实现&#xff0c;用于发送图片并以 multipart/form-data 格式进行上传。请注意&#xff0c;此代码假设图片文件路径是正确…

分类预测 | Matlab实现PSO-LSTM-Attention粒子群算法优化长短期记忆神经网络融合注意力机制多特征分类预测

分类预测 | Matlab实现PSO-LSTM-Attention粒子群算法优化长短期记忆神经网络融合注意力机制多特征分类预测 目录 分类预测 | Matlab实现PSO-LSTM-Attention粒子群算法优化长短期记忆神经网络融合注意力机制多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1…

Spring 的面向切面编程(AOP)的使用场景有哪些?

Spring 的面向切面编程&#xff08;AOP&#xff09;的使用场景有哪些&#xff1f; 文章目录 Spring 的面向切面编程&#xff08;AOP&#xff09;的使用场景有哪些&#xff1f;一、日志记录1、说明2、代码示例 二、事务管理1、说明2、代码示例 三、性能监控1、说明2、代码示例 四…

leetcode做题笔记2760. 最长奇偶子数组

给你一个下标从 0 开始的整数数组 nums 和一个整数 threshold 。 请你从 nums 的子数组中找出以下标 l 开头、下标 r 结尾 (0 < l < r < nums.length) 且满足以下条件的 最长子数组 &#xff1a; nums[l] % 2 0对于范围 [l, r - 1] 内的所有下标 i &#xff0c;num…

贪心 455.分发饼干

455.分发饼干 题目&#xff1a; 小朋友胃口值数组g[i]&#xff0c;饼干尺寸数组 s[j]&#xff0c;当饼干尺寸s[j]大于等于g[i]的时候&#xff0c;对应小朋友被满足&#xff0c;小朋友每一个最多一块饼干 &#xff0c;求给定条件下最多被满足的小朋友数量。 思路&#xff1a;…

智慧农业新篇章:拓世法宝AI智能直播一体机助力乡村振兴与农业可持续发展

随着乡村振兴战略的深入推进&#xff0c;农业发展日益成为国家关注的焦点。在这一大背景下&#xff0c;助农项目的兴起成为支持乡村振兴的一项重要举措。 乡村振兴战略的实施&#xff0c;得益于《关于推动文化产业赋能乡村振兴的意见》、《关于全面推进乡村振兴加快农业农村现…

Docker 安装 Jenkins 2.375【图文教程】

文章目录 Jenkins镜像简介Jenkins 安装及配置第 1 步: 安装Jenkins创建jenkins容器初始化Jenkins解锁jenkins自定义jenkins第 2 步:必读内容Jenkins使用root用户操作修改 Debian 镜像为阿里云镜像第 3 步: 配置Jenkins安装Locale插件:修改为中文全局工具配置JDK安装Git安装…

0x80070002错误代码要怎么解决?修复0x80070002的方法

0x80070002错误代码&#xff0c;这个系统更新相关的错误&#xff0c;经常在进行系统备份或更新时出现&#xff0c;打乱了我们的步调。为了帮助大家解决问题&#xff0c;本文将探讨该错误0x80070002产生的原因&#xff0c;提供详细的解决步骤&#xff0c;并分享预防措施。 一.0x…

Hive入门--学习笔记

1&#xff0c;Apache Hive概述 定义&#xff1a; Hive是由Facebook开源用于解决海量结构化日志的数据统计&#xff0c;它是基于大数据生态圈Hadoop的一个数据仓库工具。 作用&#xff1a; Hive可以用于将结构化的数据文件【映射】为一张表&#xff0c;并提供类SQL查询功能。 H…

leetcode每日一题-周复盘

前言 该系列文章用于我对一周中leetcode每日一题or其他不会的题的复盘总结。 一方面用于自己加深印象&#xff0c;另一方面也希望能对读者的算法能力有所帮助&#xff0c; 同时也希望能帮助同样坚持刷题的同学加深印象~ 该复盘对我来说比较容易的题我会复盘的比较粗糙&#…

clip4clip:an empirical study of clip for end to end video clip retrieval

广告深度学习计算&#xff1a;阿里妈妈智能创意服务优化使用CPU/GPU分离的多进程架构&#xff0c;加速阿里妈妈智能创意服务。https://mp.weixin.qq.com/s/_pjhXrUZVzFRtiwG2LhnkwCLIP4Clip: CLIP 再下一城&#xff0c;利用CLIP实现视频检索 - 知乎前言&#xff1a; OpenAI 的论…

ios 对话框UIAlertController放 tableview

//强弱引用 #define kWeakSelf(type)__weak typeof(type)weak##type type; -(void) showUIAlertTable {kWeakSelf(self)UIAlertController *alert [UIAlertController alertControllerWithTitle:NSLocalizedString("select_stu", nil) message:nil prefer…