【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.hqwc.cn/news/448752.html

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

相关文章

YOLO-World: Real-Time Open-Vocabulary Object Detection

文章目录 1. Introduction2. Experiments2.1 Implementation Details2.2 Pre-training2.3 Ablation Experiments2.3.1 预训练数据2.3.2 对RepVL-PAN的消融研究2.3.3 文本编码器 2.4 Fine-tuning YOLO-World2.5 Open-Vocabulary Instance Segmentation2.6 Visualizations Refere…

深度剖析Sentinel热点规则

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 深度剖析Sentinel热点规则 前言核心概念解析&#xff1a;数字守护者的起源核心概念解析&#xff1a;简单示例演示&#xff1a; 参数索引&#xff1a;规则的基石参数索引的作用&#xff1a;不同场景下选…

canvas变换中心点translate ( 图文示例 )

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

微信小程序(三十一)本地同步存储API

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.存储数据 2.读取数据 3.删除数据 4.清空数据 源码&#xff1a; index.wxml <!-- 列表渲染基础写法&#xff0c;不明白的看上一篇 --> <view class"students"><view class"item…

总分类账户和明细分类账户

目录 一. 设置二. 联系与区别三. 平行记账规则 \quad 一. 设置 \quad 根据总分类科目设置总分类账户 根据明细分类科目设置明细分类账户 \quad 二. 联系与区别 \quad \quad 三. 平行记账规则 \quad

flinkjar开发 自定义函数

编写自定义加密函数&#xff0c;继承ScalarFunction类&#xff0c;实现eval方法&#xff0c;参数个数类型和返回值根据业务来自定义。 import org.apache.flink.table.functions.ScalarFunction; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax…

关于配置系统环境变量 点击确定就显示,此环境变量过大2047

使用了网络上的所有办法,均无效 最终解决办法:把系统path环境变量里的变量环境删掉一些之后,成功加入! 原因就是path里面的内容太多了导致的,删掉一些变量就好了&#xff01;

代码随想录算法训练营29期Day41|LeetCode 343,96

文档讲解&#xff1a;整数拆分 不同的二叉搜索树 343.整数拆分 题目链接&#xff1a;https://leetcode.cn/problems/integer-break/description/ 思路&#xff1a; 题目要求我们拆分n&#xff0c;拆成k个数使其乘积和最大&#xff0c;然而题目中并没有给出k&#xff0c;所以…

day07-CSS高级

01-定位 作用&#xff1a;灵活的改变盒子在网页中的位置 实现&#xff1a; 1.定位模式&#xff1a;position 2.边偏移&#xff1a;设置盒子的位置 left right top bottom 相对定位 position: relative 特点&#xff1a; 不脱标&#xff0c;占用自己原来位置 显示模…

办公软件巨头CCED、WPS面临新考验,新款办公软件异军突起

办公软件巨头CCED、WPS的成长经历 众所周知&#xff0c;CCED和WPS在中国办公软件领域树立了两大知名品牌的地位。然而&#xff0c;它们的成功并非一朝一夕的成就&#xff0c;而是历经了长时间的发展与积淀。 在上世纪80年代末至90年代初&#xff0c;CCED作为中国大陆早期的一款…

​【c语言】函数递归

1. 递归是什么 递归是c语言学习上绕不开的话题&#xff0c;那么什么是递归呢&#xff1f; 递归实际上是自己调用自己。 2. 递归的限制条件 递归在书写的时候有两个限制条件&#xff1a; 递归存在限制条件&#xff0c;当满足这个限制条件式&#xff0c;递归将不再继续。 每…

PDF中公式转word

效果&#xff1a;实现pdf中公式免编辑 step1: 截图CtrlAltA&#xff0c;复制 step2: SimpleTex - Snip & Get 网页或客户端均可&#xff0c;无次数限制&#xff0c;效果还不错。还支持手写、文字识别 单张图片&#xff1a;选 手写板 step3: 导出结果选择 注&#xff1a;…