当前位置: 首页 > news >正文

Spring-依赖注入findAutowireCandidates源码实现

findAutowireCandidates()实现

1、找出BeanFactory中类型为type的所有的Bean的名字,根据BeanDefinition就能判断和当前type是不是匹配,不用生成Bean对象

2、把resolvableDependencies中key为type的对象找出来并添加到result中

3、遍历根据type找出的beanName,判断当前beanName对应的Bean是不是能够被自动注入

4、先判断beanName对应的BeanDefinition中的autowireCandidate属性,如果为false,表示不能用来进行自动注入,如果为true则继续进行判断

5、判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断

6、如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否定义了Qualifier,并且是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配

7、经过上述验证之后,当前beanName才能成为一个可注入的,添加到result中

/*** Find bean instances that match the required type.* Called during autowiring for the specified bean.* @param beanName the name of the bean that is about to be wired* @param requiredType the actual type of bean to look for* (may be an array component type or collection element type)* @param descriptor the descriptor of the dependency to resolve* @return a Map of candidate names and candidate instances that match* the required type (never {@code null})* @throws BeansException in case of errors* @see #autowireByType* @see #autowireConstructor*/
protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {// 从BeanFactory中找出和requiredType所匹配的beanName,仅仅是beanName,这些bean不一定经过了实例化,只有到最终确定某个Bean了,如果这个Bean还没有实例化才会真正进行实例化String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);// 根据类型从resolvableDependencies中匹配Bean,resolvableDependencies中存放的是类型:Bean对象,比如BeanFactory.class:BeanFactory对象,在Spring启动时设置for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {Class<?> autowiringType = classObjectEntry.getKey();if (autowiringType.isAssignableFrom(requiredType)) {Object autowiringValue = classObjectEntry.getValue();autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);if (requiredType.isInstance(autowiringValue)) {result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);break;}}}for (String candidate : candidateNames) {// 如果不是自己,则判断该candidate到底能不能用来进行自动注入if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}// 为空要么是真的没有匹配的,要么是匹配的自己if (result.isEmpty()) {// 需要匹配的类型是不是Map、数组之类的boolean multiple = indicatesMultipleBeans(requiredType);// Consider fallback matches if the first pass failed to find anything...DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();for (String candidate : candidateNames) {if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {addCandidateEntry(result, candidate, descriptor, requiredType);}}// 匹配的是自己,被自己添加到result中if (result.isEmpty() && !multiple) {// Consider self references as a final pass...// but in the case of a dependency collection, not the very same bean itself.for (String candidate : candidateNames) {if (isSelfReference(beanName, candidate) &&(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&isAutowireCandidate(candidate, fallbackDescriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}}}return result;
}

依赖注入中泛型注入的实现

首先在Java反射中,有一个Type接口,表示类型,具体分类为:

1、raw types:也就是普通Class

2、parameterized types:对应ParameterizedType接口,泛型类型

3、array types:对应GenericArrayType,泛型数组

4、type variables:对应TypeVariable接口,表示类型变量,也就是所定义的泛型,比如T、K

5、primitive types:基本类型,int、boolean

public class TypeTest<T>
{private int i;private Integer it;private int[] iarray;private List list;private List<String> slist;private List<T> tlist;private T t;private T[] tarray;public static void main(String[] args) throws NoSuchFieldException{test(TypeTest.class.getDeclaredField("i"));System.out.println("=======");test(TypeTest.class.getDeclaredField("it"));System.out.println("=======");test(TypeTest.class.getDeclaredField("iarray"));System.out.println("=======");test(TypeTest.class.getDeclaredField("list"));System.out.println("=======");test(TypeTest.class.getDeclaredField("slist"));System.out.println("=======");test(TypeTest.class.getDeclaredField("tlist"));System.out.println("=======");test(TypeTest.class.getDeclaredField("t"));System.out.println("=======");test(TypeTest.class.getDeclaredField("tarray"));}public static void test(Field field){if (field.getType().isPrimitive()){System.out.println(field.getName() + "是基本数据类型");}else{System.out.println(field.getName() + "不是基本数据类型");}if (field.getGenericType() instanceof ParameterizedType){System.out.println(field.getName() + "是泛型类型");}else{System.out.println(field.getName() + "不是泛型类型");}if (field.getType().isArray()){System.out.println(field.getName() + "是普通数组");}else{System.out.println(field.getName() + "不是普通数组");}if (field.getGenericType() instanceof GenericArrayType){System.out.println(field.getName() + "是泛型数组");}else{System.out.println(field.getName() + "不是泛型数组");}if (field.getGenericType() instanceof TypeVariable){System.out.println(field.getName() + "是泛型变量");}else{System.out.println(field.getName() + "不是泛型变量");}}
}

Spring中注入点是泛型的处理:

@Component
public class UserService extends BaseService<OrderService, StockService> 
{public void test() {System.out.println(o);}
}public class BaseService<O, S> 
{@Autowiredprotected O o;@Autowiredprotected S s;
}

1、Spring扫描时发现UserService是一个Bean

2、取出注入点,也就是BaseService中的两个属性o、s

3、按注入点类型进行注入,发现o和s都是泛型,所以Spring需要确定o和s的具体类型

4、当前正在创建的是UserService的Bean,所以可以通过下面这行代码获取到具体的泛型信息

userService.getClass().getGenericSuperclass().getTypeName()
返回:
com.gax.service.BaseService<com.gax.service.OrderService, com.gax.service.StockService>

5、获取UserService的父类BaseService的泛型变量

for (TypeVariable<? extends Class<?>> typeParameter : userService.getClass().getSuperclass().getTypeParameters()) 
{System._out_.println(typeParameter.getName()); 
}

6、根据第4、5步,可以知道o对应的具体就是OrderService,s对应的具体类型就是StockService

7、调用oField.getGenericType()就知道当前field使用的是哪个泛型,得到具体类型

@Qualifier的使用

定义两个注解:

@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("random")
public @interface Random {
}@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("roundRobin")
public @interface RoundRobin {
}

定义一个接口和两个实现类,表示负载均衡:

public interface LoadBalance 
{String select();
}@Component
@Random
public class RandomStrategy implements LoadBalance 
{@Overridepublic String select() {return null;}
}@Component
@RoundRobin
public class RoundRobinStrategy implements LoadBalance 
{@Overridepublic String select() {return null;}
}

使用:

@Component
public class UserService  
{@Autowired@RoundRobinprivate LoadBalance loadBalance;public void test() {System.out.println(loadBalance);}
}

相关文章:

Spring-依赖注入findAutowireCandidates源码实现

findAutowireCandidates()实现 1、找出BeanFactory中类型为type的所有的Bean的名字&#xff0c;根据BeanDefinition就能判断和当前type是不是匹配&#xff0c;不用生成Bean对象 2、把resolvableDependencies中key为type的对象找出来并添加到result中 3、遍历根据type找出的b…...

单页面应用与多页面应用的区别?

单页面应用&#xff08;SPA&#xff09;与多页面应用&#xff08;MPA&#xff09;的主要区别在于页面数量和页面跳转方式。单页面应用只有一个主页&#xff0c;而多页面应用包含多个页面。 单页面应用的优点有&#xff1a; 用户体验好&#xff1a;内容的改变不需要重新加载整…...

模型预处理的ToTensor和Normalize

模型预处理的ToTensor和Normalize flyfish import torch import numpy as np from torchvision import transformsmean (0.485, 0.456, 0.406) std (0.229, 0.224, 0.225)# data0 np.random.randint(0,255,size [4,5,3],dtypeuint8) # data0 data0.astype(np.float64) da…...

nodejs express multer 保存文件名为中文时乱码,问题解决 originalname

nodejs express multer 保存文件名为中文时乱码&#xff0c;问题解决 originalname 一、问题描述 用 express 写了个后台&#xff0c;在接收文件并保存的时候 multer 接收到的文件名为乱码。 二、解决 找了下解决方法&#xff0c;在 github 的 multer issue 中找到了答案 参…...

大数据之LibrA数据库系统告警处理(ALM-12035 恢复任务失败后数据状态未知)

告警解释 执行恢复任务失败后&#xff0c;系统会自动回滚&#xff0c;如果回滚失败&#xff0c;可能会导致数据丢失等问题&#xff0c;如果该情况出现&#xff0c;则上报告警&#xff0c;如果下一次该任务恢复成功&#xff0c;则恢复告警。 告警属性 告警ID 告警级别 可自动…...

汽车生产RFID智能制造设计解决方案与思路

汽车行业需求 汽车行业正面临着快速变革&#xff0c;传统的汽车制造方式正在向柔性化、数字化、自动化和数据化的智能制造体系转变&#xff0c;在这个变革的背景下&#xff0c;汽车制造企业面临着物流、生产、配送和资产管理等方面的挑战&#xff0c;为了应对这些挑战&#xf…...

讲解机器学习中的 K-均值聚类算法及其优缺点。

K-均值聚类算法是一种无监督学习算法&#xff0c;常用于对数据进行聚类分析。其主要步骤如下&#xff1a; 首先随机选择K个中心点&#xff08;质心&#xff09;作为初始聚类中心。 对于每一个样本&#xff0c;计算其与每一个中心点的距离&#xff0c;将其归到距离最近的中心点…...

开源DB-GPT实现连接数据库详细步骤

官方文档&#xff1a;欢迎来到DB-GPT中文文档 — DB-GPT &#x1f44f;&#x1f44f; 0.4.1 第一步&#xff1a;安装Minicoda https://docs.conda.io/en/latest/miniconda.html 第二步&#xff1a;安装Git Git - Downloading Package 第三步&#xff1a;安装embedding 模型到…...

java学习part01

15-Java语言概述-单行注释和多行注释的使用_哔哩哔哩_bilibili 1.命令行 javac编译出class文件 然后java运行 2. java文件每个文件最多一个public类 3.java注释 单行注释 // 多行注释 文档注释 文档注释内容可以被JDK提供的工具javadoc所解析&#xff0c;生成一套以网页文…...

渗透测试学习day3

文章目录 靶机&#xff1a;DancingTask 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8 靶机&#xff1a;RedeemerTask 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8Task 9Task 10Task 11 靶机&#xff1a;AppointmentTask 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8Task 9T…...

【Proteus仿真】【Arduino单片机】数码管显示

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用TM1637、共阳数码管等。 主要功能&#xff1a; 系统运行后&#xff0c;数码管显示数字、字符。 二、软件设计 /* 作者&#xff1a;嗨小易&am…...

【Bug】Python利用matplotlib绘图无法显示中文解决办法

一&#xff0c;问题描述 当利用matplotlib进行图形绘制时&#xff0c;图表标题&#xff0c;坐标轴&#xff0c;标签中文无法显示&#xff0c;显示为方框&#xff0c;并报错 运行窗口报错&#xff1a; 这是中文字体格式未导入的缘故。 二&#xff0c;解决方案 在代码import部…...

Docsify 顶部的导航是如何配置

如下图&#xff0c;我们在 Docsify 的文档中配置了一个顶部导航。 下面的步骤对顶部导航的配置进行简要介绍。 配置 有 2 个地方需要这个地方进行配置。 首先需要在 index.html 文件中的 loadNavbar: true, 配置上。 然后再在项目中添加一个 _navbar.md 文件。 在这个文件中…...

最详细的LightGBM参数介绍与深入分析

前言 我使用LightGBM有一段时间了&#xff0c;它一直是我处理大多数表格数据问题的首选算法。它有很多强大的功能&#xff0c;如果你还没有看过的话&#xff0c;我建议你去了解一下。 但我一直对了解哪些参数对性能影响最大&#xff0c;以及如何调整LightGBM参数以发挥最大作用…...

blender动画制作全流程软件

blender官网下载地址 Download — blender.org Blender是一款功能强大的免费开源的3D动画制作软件。它具有广泛的功能和工具&#xff0c;适用于从简单的2D动画到复杂的3D渲染和特效的各种需求。 以下是Blender的一些主要特点&#xff1a; 建模工具&#xff1a;Blender提供了一…...

mac的可清除空间(时间机器)

看到这个可用82GB&#xff08;458.3MB可清除&#xff09; 顿时感觉清爽&#xff0c;之前的还是可用82GB&#xff08;65GB可清除&#xff09;&#xff0c;安装个xcode都安装不上&#xff0c;费解半天&#xff0c;怎么都解决不了这个问题&#xff0c;就是买磁盘情理软件也解决不了…...

【深度学习】可交互讲解图神经网络GNN

在正式开始前&#xff0c;先找准图神经网络GNN(Graph Neural Network)的位置。 图神经网络GNN是深度学习的一个分支。 深度学习的四个分支对应了四种常见的数据格式&#xff0c;前馈神经网络FNN处理表格数据&#xff0c;表格数据可以是特征向量&#xff0c;卷积神经网络CNN处理…...

网工内推 | 运维工程师,软考认证优先,全额社保

01 北京中科网威信息技术有限公司 招聘岗位&#xff1a;运维工程师 职责描述&#xff1a; 1 熟悉网络安全标准&#xff0c;等级保护管理制度 2 负责等级保护管理制度的的企业管理要求编写&#xff1b; 3 熟系网络组网和相关安全产品&#xff1b; 4 负责用户需求挖掘、分析和…...

查找或替换excel换行符ctrl+j和word中的换行符^p,^l

一、excel中 直接上图。使用ctrlh调出替换&#xff0c;查找内容里按ctrlj&#xff08;会出现一个闪的小点&#xff09;&#xff0c;即为换行符。 二、word中 在word中&#xff0c;^p和^l分别代表换行符&#xff08;enter&#xff09;和手动换行符&#xff08;使用shiftenter&…...

pytorch_神经网络构建5

文章目录 生成对抗网络自动编码器变分自动编码器重参数GANS自动编码器变分自动编码器gans网络Least Squares GANDeep Convolutional GANs 生成对抗网络 这起源于一种思想,假如有一个生成器,从原始图片那里学习东西,一个判别器来判别图片是真实的还是生成的, 假如生成的东西能以…...

人工智能|YOLOv1的简单介绍

&#x1f31e;欢迎来到人工智能的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f339;2026年4月21日&#x1f339; ✉️希望可以和大家一起完成进阶…...

【高炉炼铁领域炉温监测、预警、调控智能体设计与应用】~系列文章04:AI如何赋能高炉炼铁?

什么是智能体&#xff1f;AI如何赋能高炉炼铁&#xff1f;第4期&#xff1a;什么是智能体&#xff1f;AI如何赋能高炉炼铁&#xff1f; &#x1f916; 概念解析 | 阅读时长&#xff1a;16分钟 | 难度&#xff1a;⭐⭐⭐&#x1f4cc; 引言 "智能体"这个词你可能听说过…...

富士胶片ApeosPort 3410SD网络扫描配置踩坑实录:从共享文件夹到SMB协议,保姆级避坑指南

富士胶片ApeosPort 3410SD网络扫描配置实战&#xff1a;共享文件夹与SMB协议深度解析 办公室里那台新到的富士胶片ApeosPort 3410SD激光一体机静静地闪着蓝灯&#xff0c;看起来人畜无害——直到你尝试配置它的网络扫描功能。作为一款面向中小企业和SOHO用户的高性价比设备&…...

用STM32的FSMC模拟8080并口驱动TFTLCD:以2.8寸屏为例的硬件级优化实践

STM32 FSMC驱动TFTLCD的硬件级优化&#xff1a;从时序解析到性能压榨 引言 在嵌入式显示领域&#xff0c;TFTLCD因其丰富的色彩表现和相对较低的功耗成为许多项目的首选。然而&#xff0c;当开发者从简单的Demo移植转向实际产品开发时&#xff0c;往往会遇到刷新率不足、CPU占用…...

告别手动改密码!Windows LAPS实战:在AD域环境里自动管理本地管理员账号

Windows LAPS实战&#xff1a;自动化域环境本地管理员密码管理指南 每次手动重置数百台域内计算机的本地管理员密码时&#xff0c;IT团队都会面临巨大压力。密码复杂度要求导致记忆困难&#xff0c;共享密码文档存在泄露风险&#xff0c;而定期轮换机制往往因为操作繁琐而流于形…...

激活函数原理与实战:从ReLU到GELU的深度解析

1. 激活函数&#xff1a;AI模型的思维开关第一次接触神经网络时&#xff0c;我盯着那些复杂的数学公式看了整整三天。直到某天深夜调试代码时&#xff0c;突然意识到激活函数就像电灯的开关——它决定了神经元是否"亮起来"。这个简单的类比让我豁然开朗&#xff0c;今…...

应用监控详解

应用监控详解 本章导读 没有监控的系统就像在黑暗中摸索——你永远不知道问题何时发生、发生在哪里。本章深入讲解APM工具、链路追踪、指标采集三大监控支柱,帮助读者构建全方位的系统可观测性,实现从被动救火到主动预防的转变。 学习目标: 目标1:理解可观测性三大支柱(Me…...

Jinger独自勇闯Microsoft AI TourShanghai

研究生凌晨奔赴上海✨ 赴一场Microsoft AI Tour之约 收获一枚纪念冰箱贴 简餐也意外合口味&#x1f35c; 最惊喜的是&#xff01; 终于和鱼皮老师合影圆梦&#x1f4f8; 打卡了上次错过的武康大楼 虽没抽到心仪大奖 但此行已是满满收获 两次赴沪皆是匆匆步履 却都藏着独一份的欢…...

新手避坑指南:用PCF85063 RTC芯片搞定项目时间,从BCD码转换到寄存器配置详解

PCF85063 RTC芯片实战指南&#xff1a;从寄存器配置到时间管理全解析 在嵌入式系统开发中&#xff0c;精确的时间管理往往是项目成功的关键要素之一。无论是构建智能家居设备、工业传感器节点还是可穿戴设备&#xff0c;实时时钟(RTC)模块都扮演着不可或缺的角色。NXP的PCF8506…...

CentOS 7下Composer报错‘missing ext-fileinfo‘?别慌,手把手教你启用PHP的fileinfo扩展

CentOS 7下PHP的fileinfo扩展缺失问题全解析与实战修复指南 当你正在CentOS 7服务器上部署一个基于ThinkPHP的项目&#xff0c;运行composer install时突然遭遇一系列关于ext-fileinfo扩展缺失的错误提示&#xff0c;这确实会让人感到措手不及。这类问题在PHP项目部署中相当常见…...