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的处理了
欢迎关注,学习不迷路!