Spring-推断构造方法

Spring中的Bean实例化对象,需要构造方法

通常一个类只有一个构造方法:

1、无参的构造方法,实例化只能选择这一个

2、有参的构造方法

  • 使用AnnotationConfigApplicationContext,会使用这个构造方法进行实例化,Spring根据构造方法的参数信息去寻找Bean,然后传给构造方法

  • 使用ClassPathXmlApplicationContext,表示使用XML的方式来使用bean。在XML中指定手动指定构造方法的参数值;或者配置autowire=constructor让Spring自动去寻找bean做为构造方法参数值。

多个构造方法情况:

1、如果开发者指定了想要使用的构造方法,那么就用这个构造方法

  • xml中的<constructor-arg>标签,表示构造方法参数,可以根据这个确定想要使用的构造方法的参数个数,从而确定想要使用的构造方法,直接指定了构造方法的参数值

  • 通过@Autowired注解,@Autowired注解可以写在构造方法上,表示开发者想使用哪个构造方法,其实是Spring通过byType+byName选择具体哪一个构造方法

2、如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动选择构造方法

  • 只能在ClassPathXmlApplicationContext中使用,可以在xml中指定某个bean的autowire为constructor,通过构造方法自动注入

3、如果开发者也没有让Spring自动选择构造方法,则Spring利用无参构造方法,如果没有无参构造方法,则报错

注意:多个构造方法上写了@Autowired注解会报错。@Autowired的属性required,默认为ture

@Autowired或@Autowired(required=true),有多个会报错

但是@Autowired(required=false)可以有多个

源码思路

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、如果没有确定的构造方法或构造方法参数值,那么

a)如果没有确定的构造方法,那么则找出类中所有的构造方法

b)如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化

c)如果有多个可用的构造方法或者当前Bean需要自动通过构造方法注入

d)根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数

e)对所有的构造方法进行排序,参数个数多的在前面

f)遍历每个构造方法

g)如果不是调用getBean方法时所指定的构造方法参数值,那么则根据构造方法参数类型找值

h)如果是调用getBean方法时所指定的构造方法参数值,就直接利用这些值

i)如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的

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

主要看计算找到的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中:

  • factoryBeanName为AppConfig所对应的beanName,比如"appConfig"

  • factoryMethodName为对应的方法名,比如"aService"

  • . factoryClass为AppConfig.class

2、如果方法不是static的,那么解析出来的BeanDefinition中:

  • factoryBeanName为null

  • factoryMethodName为对应的方法名,比如"aService"

  • 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();
}

注意:上面这种情况只会生成一个aService的Bean

假设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/136938.shtml

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

相关文章

推送效率低?MobPush带着APP消息推送一站式解决方案来了

随着移动应用竞争的日趋激烈&#xff0c;如何拉新促活&#xff0c;保持用户粘性成为各大APP的运营的焦点和核心。作为一种有效的营销和用户保留工具。APP消息推送可以有效提高用户参与度&#xff0c;增强用户忠诚度&#xff0c;并最终提高业务效益。然而随着各大APP推送的高度同…

Android 12.0 开启蓝牙状态栏即显示蓝牙图标

Android 12.0 开启蓝牙状态栏即显示蓝牙图标 最近收到客户反馈想要在开启蓝牙时状态栏就能显示出蓝牙图标&#xff0c;我们系统默认是蓝牙连接上设备后状态栏才显示出蓝牙图标&#xff0c;具体修改参照如下&#xff1a; /vendor/mediatek/proprietary/packages/apps/SystemUI…

UML与PlantUML简介

UML与PlantUML 1、UML与PlantUML概述2、PlantUML使用 1、UML与PlantUML概述 UML&#xff08;Unified Modeling Language&#xff09;是一种统一建模语言&#xff0c;为面向对象开发系统的产品进行说明、可视化、和编制文档的一种标准语言&#xff0c;独立于任何具体程序设计语言…

YOLOv8-Seg改进: 分割小目标系列篇 | SPD-Conv,提升分割小目标和弱小分割图精度

🚀🚀🚀本文改进:SPD-Conv由一个空间到深度(SPD)层和一个无卷积步长(Conv)层组成,可以应用于大多数CNN体系结构,特别是在处理低分辨率图像和分割小目标等更困难的任务时。 🚀🚀🚀SPD-Conv 分割小目标检测首选,暴力涨点 🚀🚀🚀YOLOv8-seg创新专栏:http:…

什么是Node.js的NVM(Node Version Manager)?它的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

YOLOv5检测界面-PyQt5实现

1.将detect.py运用到界面 要将 YOLOv5 的检测结果与 PyQt 界面结合&#xff0c;你需要进行一些额外的步骤。以下是一个简单的示例代码&#xff0c;展示如何使用 YOLOv5 进行目标检测并在 PyQt 界面中显示结果。 首先&#xff0c;确保你已经安装了必要的库&#xff1a; pip …

文件包含 [ZJCTF 2019]NiZhuanSiWei1

打开题目 代码审计 if(isset($text)&&(file_get_contents($text,r)"welcome to the zjctf")){ 首先isset函数检查text参数是否存在且不为空 用file_get_contents函数读取text制定的文件内容并与welcome to the zjctf进行强比较 echo "<br><h…

单源最短路的简单应用

1.dijkstra维护最长路 下面这个是讨论区的一个佬的理解&#xff0c;非常的nice 总结一句话&#xff0c;dijkstra的贪心保证了每次选定的点在之后都不会被其他点所更新了 同理维护最长路的时候我们发现&#xff0c;如果权值是0-1的话&#xff0c;选定的最大值在之后不会变的更大…

5G边缘计算网关的功能及作用

5G边缘计算网关具有多种功能。 首先&#xff0c;它支持智能云端控制&#xff0c;可以通过5G/4G/WIFI等无线网络将采集的数据直接上云&#xff0c;实现异地远程监测控制、预警通知、报告推送和设备连接等工作。 其次&#xff0c;5G边缘计算网关可以采集各种数据&#xff0c;包…

只改一个参数让Golang GC耗时暴降到1/30!

&#x1f449;导读 Golang GC 问题的处理网上有比较多的参考文章与教程&#xff0c;本文则聚焦在一次实际业务场景中遇到的问题&#xff0c;并将问题排查处理的全过程详细地做了整理记录&#xff0c;相信对各位 Gopher 有较大参考价值。 &#x1f449;目录 1 问题现象 2 确定原…

gitlab将项目转移到组中

personal 下&#xff0c;选中项目的 setting- transfer project 参考&#xff1a; https://blog.csdn.net/qq_62742127/article/details/130766898#:~:text%E6%89%93%E5%BC%80%E8%A6%81%E8%BD%AC%E7%A7%BB%E7%9A%84%E9%A1%B9%E7%9B%AE%E7%9A%84setting%20%E6%89%93%E5%BC%80Adv…

玄子Share-HTML5知识手册

玄子Share-HTML5知识手册 前言&#xff1a; 这一版 HTML 笔记&#xff0c;算是我写的第四版了&#xff0c;第三版对照课本编写&#xff0c;第四版则是对照 MDN 官方文档编写&#xff0c;不论是术语亦或专业性&#xff0c;都更上一层 文章依托 MDN 文档&#xff0c;拓展了大量课…

【论文解读】针对生成任务的多模态图学习

一、简要介绍 多模态学习结合了多种数据模式&#xff0c;拓宽了模型可以利用的数据的类型和复杂性&#xff1a;例如&#xff0c;从纯文本到图像映射对。大多数多模态学习算法专注于建模来自两种模式的简单的一对一数据对&#xff0c;如图像-标题对&#xff0c;或音频文本对。然…

vue2手机项目如何使用蓝牙功能

要在Vue2手机项目中使用蓝牙功能&#xff0c;你需要先了解基本的蓝牙知识和API。以下是一些基本的步骤&#xff1a; 确认你的手机设备支持蓝牙功能。在Vue2项目中安装蓝牙插件或库&#xff0c;例如vue-bluetooth或vue-bluetooth-manager。你可以通过npm安装它们。在Vue2项目中…

老师还不会评课?这里有你需要的解决方案

优点&#xff1a; 1.课件制作: 老师的PPT设计得很新颖&#xff0c;插入的音乐视频都非常贴合课堂内容&#xff0c;看得出老师非常用心地进行了设计。 2.教师素养&#xff1a;老师的语言丰富、朗读能力很出色、板书设计很工整。 3.教师风格: xx老师上课激情澎湃/非常有亲和力…

Node.js |(六)express框架 | 尚硅谷2023版Node.js零基础视频教程

学习视频&#xff1a;尚硅谷2023版Node.js零基础视频教程&#xff0c;nodejs新手到高手 文章目录 &#x1f4da;express使用&#x1f407;初体验&#x1f407;express路由⭐️路由的使用⭐️获取请求参数⭐️获取路由参数&#x1f525;练习&#xff1a;根据路由参数响应歌手信息…

AJAX 入门笔记

课程地址 AJAX Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09; AJAX 不是新的编程语言&#xff0c;而是一种使用现有标准的新方法 AJAX 最大的优点是在不重新加载整个页面的情况下&#xff0c;可以与服务器交换数据并更新部分网页内容 XML…

C++初阶(九)内存管理

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、C/C内存分布1、选择题2、填空题3、sizeof 和 strlen 区别&#xff1f;4、总结 二、 C语言…

LED热仿真笔记

LED的输入电能主要转换为热能和光能两个部分。对于车灯散热、建筑热舒适性等计算域尺寸远大于单个LED尺寸的问题&#xff0c;通常不考虑LED的细节结构&#xff0c;LED简化为一个实体即可。 LED热源加载处理&#xff1a; 热能简化为LED实体的体热源光能简化为LED实体的发光面的…

适用于 iOS 的 10 个最佳数据恢复工具分享

在当今的数字时代&#xff0c;我们的移动设备占据了我们生活的很大一部分。从令人难忘的照片和视频到重要的文档和消息&#xff0c;我们的 iOS 设备存储了大量我们无法承受丢失的数据。然而&#xff0c;事故时有发生&#xff0c;无论是由于软件故障、无意删除&#xff0c;甚至是…