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

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 {
    // 略...

    // 所需要的类型是Optional
    if (Optional.class == descriptor.getDependencyType()) {
        return createOptionalDependency(descriptor, requestingBeanName);
    }
    // 略...
}


private Optional<?> createOptionalDependency(DependencyDescriptor descriptor, @Nullable String beanName, final Object... args) {
    // 构造一个NestedDependencyDescriptor
    DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {
        @Override
        public boolean isRequired() { // 重写isRequired,表示不需要真正找到Bean
            return false;
        }
        @Override
        public 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);
        // 嵌套级别+1
        increaseNestingLevel();
    }
    
}
// 嵌套级别+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.kler.cn/a/146918.html

相关文章:

  • PhpSpreadsheet导出图片
  • WebAssembly在桌面级应用开发中的探索与实践
  • 基于Python的仓库管理系统设计与实现
  • python语言基础-5 进阶语法-5.2 装饰器-5.2.2 简单装饰器
  • Sql进阶:字段中包含CSV,如何通过Sql解析CSV成多行多列?
  • LeetCode 445.两数相加 II
  • 【LeetCode】挑战100天 Day14(热题+面试经典150题)
  • Using Application Engine Meta-SQL 使用应用引擎元SQL
  • Java制作“简易王者荣耀”小游戏
  • MySQL日期函数sysdate()与now()的区别,获取当前时间,日期相关函数
  • 再探Docker:从Docker基础到跨服务器部署
  • 京东平台双11全品类完整销售数据回顾(京东大数据-京东数据采集-京东数据接口)
  • 什么是机器学习
  • 概念理论类: Linux的管道机制
  • 生成EtherCAT从站XML图片信息方法
  • VR全景技术助力政务服务大厅数字化,打造全新政务服务体验
  • Python字典合并
  • Java远程连接本地开源分布式搜索引擎ElasticSearch
  • 部署kafka
  • ZKP11.4 Use CI to instantiate Fiat-Shamir
  • 探索编程在现代社会的无限价值
  • 12 网关实战:Spring Cloud Gateway基础理论
  • Python break用法详解
  • [socket 弹 shell] msg_box3
  • 虹科干货 | 适用于基于FPGA的网络设备的IEEE 1588透明时钟架构
  • 线上异步任务突然不能回写100%