【Spring源码分析】推断构造方法

推断构造方法源码解析

  • 一、确认候选构造——AutowireAnnotationBeanPostProcessor#determineCandidateConstructors
  • 二、autowireConstructor 方法源码解析
  • 三、总结

阅读此需阅读下面这些博客先
【Spring源码分析】Bean的元数据和一些Spring的工具
【Spring源码分析】BeanFactory系列接口解读
【Spring源码分析】执行流程之非懒加载单例Bean的实例化逻辑
【Spring源码分析】从源码角度去熟悉依赖注入(一)
【Spring源码分析】从源码角度去熟悉依赖注入(二)
【Spring源码分析】@Resource注入的源码解析
【Spring源码分析】循环依赖的底层源码剖析

Spring 在推断构造方法的逻辑上面写的实在太复杂了,构造种类贼多贼多,恕我实力有限,这里的话算不上源码分析,只能说是原理吧,这我只考虑了平常开发会遇到的,什么getBean去添加参数的、BeanDefinition去填充的我都一概跳过,看不懂一点(比如多参构造参数相同的情况下(@Autowired注解修饰后的required为false)会进行评分操作,有点复杂,感觉遇不着就不想研究了)。

(这篇博客可能有点水了)

在这里插入图片描述

一、确认候选构造——AutowireAnnotationBeanPostProcessor#determineCandidateConstructors

确认候选的构造也是通过 BeanPostProcessor 来进行的(SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors),引进的代码如下:

		// Candidate constructors for autowiring?// 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中的哪些构造方法// 比如AutowiredAnnotationBeanPostProcessor会把加了@Autowired注解的构造方法找出来,具体看代码实现会更复杂一点Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);@Nullableprotected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)throws BeansException {if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);if (ctors != null) {return ctors;}}}return null;}

Spring 实现的 SmartInstantiationAwareBeanPostProcessor 的 determineCandidateConstructors 方法中就一个对其进行实现了——AutowireAnnotationBeanPostProcessor。

下面俺对其核心代码进行解析:

	@Override@Nullablepublic Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)throws BeanCreationException {// Quick check on the concurrent map first, with minimal locking.Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);if (candidateConstructors == null) {// Fully synchronized resolution now...synchronized (this.candidateConstructorsCache) {candidateConstructors = this.candidateConstructorsCache.get(beanClass);if (candidateConstructors == null) {Constructor<?>[] rawCandidates;try {// 拿到所有的构造方法rawCandidates = beanClass.getDeclaredConstructors();} catch (Throwable ex) {throw new BeanCreationException(beanName,"Resolution of declared constructors on bean Class [" + beanClass.getName() +"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);}List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);// 用来记录required为true的构造方法,一个类中只能有一个required为true的构造方法Constructor<?> requiredConstructor = null;// 用来记录默认无参的构造方法Constructor<?> defaultConstructor = null;// 遍历每个构造方法for (Constructor<?> candidate : rawCandidates) {// 当前遍历的构造方法是否写了@AutowiredMergedAnnotation<?> ann = findAutowiredAnnotation(candidate);// 当前构造方法上加了@Autowiredif (ann != null) {// 整个类中如果有一个required为true的构造方法,那就不能有其他的加了@Autowired的构造方法// 若存在required为true的还存在其他的@Autowired注解就抛出异常if (requiredConstructor != null) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructor: " + candidate +". Found constructor with 'required' Autowired annotation already: " +requiredConstructor);}boolean required = determineRequiredStatus(ann);if (required) {if (!candidates.isEmpty()) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructors: " + candidates +". Found constructor with 'required' Autowired annotation: " +candidate);}// 记录唯一一个required为true的构造方法requiredConstructor = candidate;}// 记录所有加了@Autowired的构造方法,不管required是true还是false// 如果默认无参的构造方法上也加了@Autowired,那么也会加到candidates中candidates.add(candidate);// 从上面代码可以得到一个结论,在一个类中,要么只能有一个required为true的构造方法,要么只能有一个或多个required为false的方法} else if (candidate.getParameterCount() == 0) {// 记录唯一一个无参的构造方法defaultConstructor = candidate;}// 有可能存在有参、并且没有添加@Autowired的构造方法}if (!candidates.isEmpty()) {// Add default constructor to list of optional constructors, as fallback.// 如果不存在一个required为true的构造方法,则所有required为false的构造方法和无参构造方法都是合格的if (requiredConstructor == null) {if (defaultConstructor != null) {candidates.add(defaultConstructor);} else if (candidates.size() == 1 && logger.isInfoEnabled()) {logger.info("Inconsistent constructor declaration on bean with name '" + beanName +"': single autowire-marked constructor flagged as optional - " +"this constructor is effectively required since there is no " +"default constructor to fall back to: " + candidates.get(0));}}// 如果只存在一个required为true的构造方法,那就只有这一个是合格的candidateConstructors = candidates.toArray(new Constructor<?>[0]);}// 没有添加了@Autowired注解的构造方法,并且类中只有一个构造方法,并且是有参的else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {candidateConstructors = new Constructor<?>[]{rawCandidates[0]};}else {// 如果有多个有参、并且没有添加@Autowired的构造方法,是会返回空的candidateConstructors = new Constructor<?>[0];}this.candidateConstructorsCache.put(beanClass, candidateConstructors);}}}return (candidateConstructors.length > 0 ? candidateConstructors : null);}

在这里插入图片描述
就是说只有三种情况有可用的构造(这里是指会有返回的候选构造方法):

  • 使用了 @Autowired 注解,有且只有一个 required 为 true;
  • 使用了 @Autowired 注解,required 都为 false;
  • 没有使用 @Autowired 注解,有且只有一个多参构造。

在这里插入图片描述通过这些代码的解析可以知道:

  • 含有多个参数多个构造和只有一个无参的都会走 instantiateBean 的逻辑,去通过无参构造去实例化,如果没有的话就抛异常咯,换句话说就是没用@Autowired注解就是去找无参,没有就抛异常
    • 在这里插入图片描述
    • 在这里插入图片描述
  • 有且只有一个 @Autowired 注解且required为true,有多个 @Autowired 注解,但是 required 都为 false,那么就是通过 autowireConstructor 方法去实现 Spring 的自动构造。

二、autowireConstructor 方法源码解析

太难了,看不了一点,直接阐述源码流程(和上面的接着的)。

上面确认候选构造的时候还有三种情况我们需要考虑:

  • 使用了 @Autowired 注解,有且只有一个 required 为 true;
  • 使用了 @Autowired 注解,required 都为 false;
  • 没有使用 @Autowired 注解,有且只有一个多参构造。

也就是上面这三种情况会进入到 autowireConstructor 方法。
下面阐述一下流程:

  1. 首先是对构造进行个排序,以参数的个数降序排序,就是参数个数多的在前面:
    • 在这里插入图片描述
  2. 然后去调用 beanFactory#resolveDependency 方法去给参数进行填充参数;
  3. 如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的
    • 在这里插入图片描述
    • 在这里插入图片描述
      也就是说构造方法要满足可用的话,必须所有的参数都是Spring容器中拥有的,可以注入的。

三、总结

本篇并不是Spring所有推断构造方法的逻辑,只是其中的一部分——AutowireAnnotationBeanPostProcessor#determineCandidateConstructors 中推断出来的构造方法是怎么处理的。

主要就是有无 @Autowired 注解俩各方面。

在这里插入图片描述当有多个构造 @Autowired 注解,但是 required 都为 false 的话,考虑 autowireConstructor 的逻辑。先是将所候选的构造参数个数降序排序,然后逐个去匹配,看看参数是否都能在容器中找到,找不到就换下一个,找到就用该构造。

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

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

相关文章

基于大数据的淘宝电子产品数据分析的设计与实现

&#xff08;1&#xff09;本次针对开发设计系统并设置了相关的实施方案&#xff0c;利用完整的软件开发流程进行分析&#xff0c;完成了设置不同用户的操作权限和相关功能模块的开发&#xff0c;最后对系统进行测试。 &#xff08;2&#xff09;框架可以帮助程序开发者快速构建…

Gson源码解读

一&#xff0c;概述 gson作为流行的json工具&#xff0c;笔者使用较多。本文主要目的是解读下Gson的源码实现&#xff0c;就没有然后了。 二&#xff0c;实例 实例如下图所示&#xff0c;笔者简单调用gson的toJson方法获得json字符串&#xff0c;fromJson则从json字符串解析…

Cmake语法学习2:常用变量

目录 1.常用变量简介 1.1提供信息的变量 1.2改变行为的变量 1.3描述系统的变量 ​编辑1.4控制编译的变量 2.提供信息的变量 2.1PROJECT_SOURCE_DIR 和 PROJECT_BINARY_DIR 2.2 CMAKE_SOURCE_DIR 和 CMAKE_BINARY_DIR 2.3CMAKE_CURRENT_SOURCE_DIR 和CMAKE_CURRENT_BIN…

【文件上传WAF绕过】<?绕过、.htaccess木马、.php绕过

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

【笔记】React Native实战练习(仿网易云游戏网页移动端)

/** * 如果系统看一遍RN相关官方文档&#xff0c;可能很快就忘记了。一味看文档也很枯燥无味&#xff0c; * 于是大概看了关键文档后&#xff0c;想着直接开发一个Demo出来&#xff0c;边学边写&#xff0c;对往后工作 * 开发衔接上能够更顺。这期间肯定会遇到各种各样的问题&a…

Qt 范例阅读: QStateMachine状态机框架 和 SCXML 引擎简单记录(方便后续有需求能想到这两个东西)

一、QStateMachine 简单应用&#xff1a; 实现按钮的文本切换 QStateMachine machine; //定义状态机&#xff08;头文件定义&#xff09;QState *off new QState(); //添加off 状态off->assignProperty(ui->pushButton_2, "text", "Off"); //绑定该…

025 break,continue,goto

什么是break for (int i 1; i < 10; i) {if(i 5){break;}System.out.println(i); } // 结果为 1 2 3 4 什么是continue for (int i 1; i < 10; i) {if(i 5){continue;}System.out.println(i); } // 结果为 1 2 3 4 6 7 8 9 关于goto关键字 String str ""…

2024年美国大学生数学建模竞赛(C题)探寻网球中的“动量”奥秘|DQN算法和Monte Carlo模拟建模解析,小鹿学长带队指引全代码文章与思路

我是小鹿学长&#xff0c;就读于上海交通大学&#xff0c;截至目前已经帮200人完成了建模与思路的构建的处理了&#xff5e; 探寻网球比赛中的“动量”奥秘&#xff01;鹿鹿学长独辟蹊径&#xff0c;运用强化学习与时间序列分析相结合&#xff0c;以DQN和Monte Carlo模拟实现对…

完整的 HTTP 请求所经历的步骤及分布式事务解决方案

1. 对分布式事务的了解 分布式事务是企业集成中的一个技术难点&#xff0c;也是每一个分布式系统架构中都会涉及到的一个东西&#xff0c; 特别是在微服务架构中&#xff0c;几乎可以说是无法避免。 首先要搞清楚&#xff1a;ACID、CAP、BASE理论。 ACID 指数据库事务正确执行…

基于数据挖掘的微博事件分析与可视化大屏分析系统

设计原理&#xff0c;是指一个系统的设计由来&#xff0c;其将需求合理拆解成功能&#xff0c;抽象的描述系统的模块&#xff0c;以模块下的功能。功能模块化后&#xff0c;变成可组合、可拆解的单元&#xff0c;在设计时&#xff0c;会将所有信息分解存储在各个表中&#xff0…

【论文解读】Collaboration Helps Camera Overtake LiDAR in 3D Detection

CoCa3D 摘要引言Collaborative Camera-Only 3D DetectionCollaborative depth estimationCollaborative detection feature learning 实验结论和局限 摘要 与基于 LiDAR 的检测系统相比&#xff0c;仅相机 3D 检测提供了一种经济的解决方案&#xff0c;具有简单的配置来定位 3…

MySQL进阶45讲【11】怎么更好地给字符串字段加索引?

1 前言 现在&#xff0c;几乎所有的系统都支持邮箱登录&#xff0c;如何在邮箱这样的字段上建立合理的索引&#xff0c;是我们今天要讨论的问题。 假设&#xff0c;现在维护一个支持邮箱登录的系统&#xff0c;用户表是这么定义的&#xff1a; mysql> create table SUser…

删除有序数组中的重复项 II[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你一个有序数组nums&#xff0c;请你原地删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。不要使用额外的数组空间&#xff0c;你必须在原地修改输入数组并在使用O(1)额…

jvm基础篇之垃圾回收[2](垃圾回收算法)

文章目录 版权声明垃圾回收算法核心思想垃圾回收算法的历史垃圾回收算法的评价标准垃圾分类算法分类标记清除算法核心思想标记清除算法优缺点 复制算法核心思想完整案例复制算法的优缺点 标记整理算法核心思想标记整理算法优缺点 分代垃圾回收算法arthas查看分代内存情况核心思…

stm32软件安装以及创建工程

文章目录 前言一、软件安装软件破解 二、创建工程三、创建项目创建组配置启动文件添加到组 为项目添加头文件路径创建源文件&#xff08;main函数文件&#xff09;使用寄存器配置引脚拼接好STLINK与stm32最小电路板的接线编写程序配置STLink下载程序配置寄存器配置13号端口&…

用户体验优化:HubSpot的秘密武器

在当今数字化市场中&#xff0c;提升用户体验已经成为企业成功的关键因素之一。HubSpot&#xff0c;作为一款领先的营销自动化工具&#xff0c;不仅在推动销售业绩上表现出色&#xff0c;同时通过其独特的策略也致力于提升用户体验。运营坛将深入探讨HubSpot是如何通过个性化推…

Leetcode—41. 缺失的第一个正数【困难】

2024每日刷题&#xff08;一零九&#xff09; Leetcode—41. 缺失的第一个正数 实现代码 class Solution { public:int firstMissingPositive(vector<int>& nums) {int n nums.size();// nums[i] i 1;// nums[i] - 1 i;// nums[nums[i] - 1] nums[i];for(int …

能源管理新高度DI/DO/CAN/RS485/USB网关助力二次开发

能源管理领域正在寻求更为智能化和高效的解决方案。一款集成了先进ARM架构处理器的边缘计算能源储能网关应运而生&#xff0c;以其卓越的性能和丰富的接口功能吸引了众多行业用户的关注。 这款网关不仅配备有常规的数字输入&#xff08;DI&#xff09;、数字输出&#xff08;DO…

【简便方法和积累】pytest 单元测试框架中便捷安装插件和执行问题

又来进步一点点~~~ 背景&#xff1a;之前写了两篇关于pytest单元测试框架的文章&#xff0c;本篇内容对之前的做一个补充 一、pytest插件&#xff1a; pytest 有非常多的插件&#xff0c;很方便&#xff0c;以下为插件举例&#xff1a; pytest&#xff0c;pytest-html&#x…

新手从零开始学习数学建模论文写作(美赛论文临时抱佛脚篇)

本文记录于数学建模老哥视频的学习过程中。b站视频&#xff1a;http://【【零基础教程】老哥&#xff1a;数学建模算法、编程、写作和获奖指南全流程培训&#xff01;】https://www.bilibili.com/video/BV1kC4y1a7Ee?p50&vd_sourceff53a726c62f94eda5f615bd4a62c458 目录…