28. Spring源码篇依赖注入之Optional

简介

我们知道,java中的Optional是解决臭名昭著的空指针异常,在spring的依赖注入中,如果没有找到Bean也会抛异常,就算将required写为false,后面也会需要判空

在spring中也支持Optional的依赖注入

创建Optional

java8中创建Optional的api如下

Optional.of(T t)            创建一个 Optional 对象,参数 t 必须非空,如果你把 null 值作为参数传递进去,of() 方法会抛出 NullPointerException
Optional.empty()	        创建一个空的 Optional 实例
Optional.ofNullable(T t)    创建一个 Optional 对象,如果参数 t 为非空,返回 Optional 描述的指定值,否则返回空的 Optional

使用

如果是一个普通的Bean注入,但是却找不到Bean,那么会抛异常,例如

为了好输出内容,使用构造器注入

@Component
public class OptionalBean {public OptionalBean(String obj) {System.out.println(obj);}}

报错

No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

如果将字段类型Optional那么就不会报错

@Component
public class OptionalBean {public OptionalBean(Optional<String> obj) {System.out.println(obj);}
}输出
Optional.empty

源码解析

代码在依赖描述器处理逻辑里面,至于什么是依赖描述器后面文章详细介绍

org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {// 略...// 所需要的类型是Optionalif (Optional.class == descriptor.getDependencyType()) {return createOptionalDependency(descriptor, requestingBeanName);}// 略...
}private Optional<?> createOptionalDependency(DependencyDescriptor descriptor, @Nullable String beanName, final Object... args) {// 构造一个NestedDependencyDescriptorDependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {@Overridepublic boolean isRequired() { // 重写isRequired,表示不需要真正找到Beanreturn false;}@Overridepublic Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {return (!ObjectUtils.isEmpty(args) ? beanFactory.getBean(beanName, args) :super.resolveCandidate(beanName, requiredType, beanFactory));}};// 依赖注入Object result = doResolveDependency(descriptorToUse, beanName, null, null);// 如果result为null,那么将构造一个空的Optional,否则也是返回一个Optional但是非空return (result instanceof Optional ? (Optional<?>) result : Optional.ofNullable(result));
}// NestedDependencyDescriptor类
private static class NestedDependencyDescriptor extends DependencyDescriptor {public NestedDependencyDescriptor(DependencyDescriptor original) {super(original);// 嵌套级别+1increaseNestingLevel();}}
// 嵌套级别+1
public void increaseNestingLevel() {this.nestingLevel++;this.resolvableType = null;if (this.methodParameter != null) {this.methodParameter = this.methodParameter.nested();}
}

从上面逻辑就可以看出,其实就是不管找没找到值都是返回一个Optional,不会强制一定要找到Bean

那么如果是一个Optional,该怎么知道真实的类型呢。跟上面构造的NestedDependencyDescriptor有关系,嵌套级别+1

下面是获取Bean类型的代码


public Class<?> getDependencyType() {if (this.field != null) {// 如果是Optional,这里nestingLevel为2,表示有一层嵌套if (this.nestingLevel > 1) {Type type = this.field.getGenericType();// 循环嵌套层数,拿到真实的类型for (int i = 2; i <= this.nestingLevel; i++) {if (type instanceof ParameterizedType) {// 拿到真实的类型Type[] args = ((ParameterizedType) type).getActualTypeArguments();type = args[args.length - 1];}}if (type instanceof Class) {return (Class<?>) type;}else if (type instanceof ParameterizedType) {Type arg = ((ParameterizedType) type).getRawType();if (arg instanceof Class) {return (Class<?>) arg;}}return Object.class;}else {return this.field.getType();}}else {return obtainMethodParameter().getNestedParameterType();}
}

以上就是spring对Optional的处理了


欢迎关注,学习不迷路!

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

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

相关文章

【TinyALSA全解析(一)】TinyALSA简介

TinyALSA简介 一、TinyALSA概述1.1 TinyALSA背景和用途1.2 TinyALSA主要内容1.3 TinyALSA与ALSA的关系 二、TinyALSA具体有哪些内容2.1 libtinyalsa.so 库2.2 一组工具 三、tinyalsa完整目录分析四、tinyalsa的编译方法和使用方法4.1 tinyalsa编译方法4.1.1 TinyALSA全编译方法…

【JVM系列】- 穿插·对象的实例化与直接内存

对象的实例化与直接内存 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xff0c;大家一起学习成长&#xff01; 文章目录…

SpringCloud系列文章目录(总纲篇)

文章目录 前言正文一、原理性文章1.1 OpenFeign篇 二、实战性文章1.1 注册中心、配置中心篇1.2 网关篇1.3 OpenFeign篇 前言 SpringCloud系列文章&#xff0c;有些文章上下文存在联系。 并且&#xff0c;它们数量巨多&#xff0c;有涉及原理的&#xff0c;有涉及实战的。 本文…

域名邮箱与企业邮箱的区别:功能、应用与优势

根据使用者的不同需求&#xff0c;电子邮件分为域名邮箱和企业邮箱两种类型。那么这两种邮箱之间究竟存在哪些区别呢&#xff1f;本文将从定义、优势和劣势三个方面进行详细解析。 什么是域名邮箱&#xff1f; 域名邮箱&#xff0c;顾名思义是以域名作为后缀的电子邮箱。域名邮…

【UGUI】制作用户注册UI界面

这里面主要的操作思想就是 1.打组 同一个事情里面包含两个UI元素都应该打组便于管理和查找 2.设置锚点位置 每次创建一个UI都应该设置他的锚点以便于跟随画布控制自己的&#xff1a;相对位置 3. 设置尺寸&#xff08;像素大小&#xff09; 每一次UI元素哪怕是作为父物体的…

我叫:归并排序【JAVA】

1.认识我一下 1.归并排序(MERGE-SORT)利用归并的思想实现的排序方法,该算法采用经典的分治策略2.分治法将问题分成一些小的问题然后递归求解,而治的阶段则将分的阶段得到的各答案"修补"在一起&#xff0c;即分而治之。 2.分合思想 3 分久必合 /*** 合并** param arr …

tp6框架 万级数据入库

用框架自带的saveall方法 当数据超过一千就会出现遗漏的情况 下面是原生sql方法&#xff1a; function saveCourse($newArr, $count) {$sql "replace into edu_wx_school_self_course (study_hour,code,cn_name,en_name,study_score,school_qy) values";for ($a…

(数据结构)顺序表的定义

#include<stdio.h> //顺序表的实现——静态分配 #define MAX 10 //定义最大长度 typedef struct List {int data[MAX]; //用静态的数组存放数据int lenth; //顺序表现在的长度 }List; //顺序表的初始化 void ChuShiHua(List L) {L.lenth 0; //将顺序表的长度初始化…

Tensorflow检测不到GPU解决办法(针对本人4060有效)

目录 前置条件硬件条件当前日期 检查方法解决方法版本列表tensorflow2.10.0CUDA12.1cudnn8.8 结果 前置条件 硬件条件 R5-5600G RTX4060 当前日期 当前时间是2023年11月27日&#xff0c;请注意本文的时效性&#xff0c;保不齐后续出现某个组件的更新能够直接解决这个问题。…

YOLOv8优化策略:自适应改变核大小卷积AKConv,效果优于标准卷积核和DSConv |2023.11月最新成果

🚀🚀🚀本文改进: AKConv 中,通过新的坐标生成算法定义任意大小的卷积核的初始位置。 为了适应目标的变化,引入了偏移量来调整每个位置的样本形状。 此外,我们通过使用具有相同大小和不同初始采样形状的 AKConv 来探索神经网络的效果。 AKConv 通过不规则卷积运算完成…

STM32项目经验分享:常用软件

文章目录 硬件设计软件软件设计软件英文文档阅读 硬件设计软件 Altium Designer&#xff08;在公司用会被维权&#xff09; 3D模型&#xff08;3D contentcentral&#xff09; 嘉立创 先用立创EDA画原理图然后再用AD画PCB,3D模型可以用3D contentcentral下载 软件设计软件 …

【备忘录】软件记录

Anaconda 虚拟环境 创建Python环境 Spyder Python程序编辑 Jupyter Notebook 交互式开发环境

Spring第二课响应的完全,如何理解前后端互联

目录 一、响应 Control,RestController 1.Controller的源码&#xff0c;代表什么意思 2.返回数据 Responsebody 3.返回HTML片段 4.返回JSON 5.那么假如我们使用集合会怎么样呢 设置状态码&#xff0c;虽然不影响展示&#xff0c;但是确实显示起来也就是401的情况。 2.我…

[设计模式] 常见的设计模式

文章目录 设计模式的 6 大设计原则设计模式的三大分类常见的设计模式有哪几种1. 单例模式&#xff1a;保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。&#xff08;连接池&#xff09;1. 饿汉式2. 懒汉式3. 双重检测 2. 工厂模式3. 观察者模式● 推模型● 拉…

自动化横行时代,手工测试如何突破重围?测试之路...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 自动化测试是每个…

WiseAlign 软件运行中存图功能使用方法

WiseAlign 软件运行中存图功能使用方法 在需要存图的相机图像通道点击鼠标右键 在弹出的菜单中选择“图像操作——保存图像” 选择想要存放图片的文件夹&#xff08;如下图所示&#xff09; 修改文件名称 如果文件夹中已有同名文件会提示xxx.bmp文件已存在&#xff0c;是否需要…

【【Linux开发环境搭建与软件的安装】】

Linux开发环境搭建与软件的安装 下面我们来讲述 Ubuntu 系统搭建 tftp 服务器 TFTP 需要一个文件夹来存放文件&#xff0c;我们在根目录下新建一个/tftpboot 目录做为 TFTP 文件存储目录&#xff0c;之所以使用该目录是因为后面使用的 Petalinux 工具默认使用该目录&#xff0…

Spring Cloud,注册中心,配置中心,原理详解

文章目录 Spring Cloud&#xff0c;注册中心&#xff0c;配置中心&#xff0c;原理详解谈谈我个人对 spring Cloud 的理解 注册中心Eureka&#xff1a;服务搭建小结 Ribbo - 负载均衡1. 负载均衡流程2. 负载均衡策略 nacos注册中心1. 配置集群1. 创建 namespace2. 配置命名空间…

核密度估计法(KDE)的概念,应用,优点,缺点,以及与正态分布(高斯分布)的区别,以及与概率分布的区别联系。看完你就真正捋清这些概念了

文章目录 前言一、核密度估计法&#xff08;KDE&#xff09;是什么&#xff1f;二、核密度估计法的步骤如下&#xff1a;三、核密度的应用&#xff1a;四、核密度估计法的优点&#xff1a;五、核密度估计法的缺点&#xff1a;六、核密度估计法和正态分布的区别在于&#xff1a;…

注解方式优雅的实现Redisson分布式锁

1.前言 随着微服务的快速推进&#xff0c;分布式架构也得到蓬勃的发展&#xff0c;那么如何保证多进程之间的并发则成为需要考虑的问题。因为服务是分布式部署模式&#xff0c;本地锁Reentrantlock和Synchnorized就无法使用了&#xff0c;当然很多同学脱口而出的基于Redis的se…