zoukankan      html  css  js  c++  java
  • Spring 是如何解析泛型

    Spring 是如何解析泛型 - ResolvalbeType

    Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

    Java Type 泛型系列文章:

    1. Java - Type 介绍
    2. Java - Type 的获取方式
    3. Spring - ResolvableType

    Spring 中大量使用反射,需要获取泛型的具体类型,为此专门提供了一个工具类解析泛型 - ResolvalbeType。ResolvableType 是对 Class,Field,Method 获取 Type 的抽象。

    一、ResolvalbeType 使用

    interface Service<N, M> {
    }
    class ServiceImpl<A, B> implements Service<String, Integer> {
        public ServiceImpl(List<List<String>> list, Map<Double, Map<Float, Integer>> map) {
        }
    }
    

    (1) forClass

    @Test
    public void forClassTest() {
        ResolvableType resolvableType = ResolvableType.forClass(ServiceImpl.class);
        // getType 保存原始的 Type 类型
        Assert.assertEquals(ServiceImpl.class, resolvableType.getType());
        // resolve 将 Type 解析为 Class, 如果无法解析返回 null
        Assert.assertEquals(ServiceImpl.class, resolvableType.resolve());
    }
    

    (2) forField

    private Service<Double, Float> service;
    private List<List<String>> list;
    private Map<String, Map<String, Integer>> map;
    private List<String>[] array;
    
    @Test
    public void forFieldTest() {
        // 1. Service<Double, Float> service
        Field filed = ReflectionUtils.findField(ResolveTypeTest.class, "service");
        ResolvableType resolvableType = ResolvableType.forField(filed);
        // getType() 保存原始的 Type 类型
        Assert.assertEquals(filed.getGenericType(), resolvableType.getType());
        // resolve() 对于 ParameterizedType 类型保存的是 <> 之前的类型,即 Service.class
        Assert.assertEquals(((ParameterizedType) filed.getGenericType()).getRawType(), resolvableType.resolve());
        
        Class<?> clazz = resolvableType.getGeneric(0).resolve();
        Assert.assertEquals(Double.class, clazz);
    
        // 2. List<List<String>> list
        resolvableType = ResolvableType.forField(
                ReflectionUtils.findField(ResolveTypeTest.class, "list"));
        // 下面两种获取泛型的方式等价
        clazz = resolvableType.getGeneric(0).getGeneric(0).resolve();
        Assert.assertEquals(String.class, clazz);    
        clazz = resolvableType.getGeneric(0, 0).resolve();
        Assert.assertEquals(String.class, clazz);
    
        // 3. Map<String, Map<String, Integer>> map
        resolvableType = ResolvableType.forField(
                ReflectionUtils.findField(ResolveTypeTest.class, "map"));
        clazz = resolvableType.getGeneric(1).getGeneric(1).resolve();
        Assert.assertEquals(Integer.class, clazz);
    
        // 4. List<String>[] array
        resolvableType = ResolvableType.forField(
                ReflectionUtils.findField(ResolveTypeTest.class, "array"));
        Assert.assertTrue(resolvableType.isArray());
        Assert.assertEquals(List.class, resolvableType.getComponentType().resolve());
        Assert.assertEquals(String.class, resolvableType.getComponentType().getGeneric(0).resolve());
    }
    

    (3) forMethodParameter

    forMethodParameter 还有很多变种:如 forConstructorParameter、forMethodReturnType

    @Test
    public void forMethodTest() {
        // 1. 方法的返回值类型
        ResolvableType returnType = ResolvableType.forMethodReturnType(
                ReflectionUtils.findMethod(ServiceImpl.class, "method"));
        Assert.assertEquals(Double.class, returnType.getGeneric(1, 0).resolve());
    
        // 2. 构造器 ServiceImpl(List<List<String>> list, Map<Double, Map<Float, Integer>> map)
        ResolvableType parameterType = ResolvableType.forConstructorParameter(
                ClassUtils.getConstructorIfAvailable(ServiceImpl.class, List.class, Map.class), 0);
        // List<List<String>> 的泛型第一层为 <List<String>>,第二层为 <String>
        Assert.assertEquals(String.class, parameterType.getGeneric(0, 0).resolve());
    
        parameterType = ResolvableType.forConstructorParameter(
                ClassUtils.getConstructorIfAvailable(ServiceImpl.class, List.class, Map.class), 1);
        Assert.assertEquals(Double.class, parameterType.getGeneric(0).resolve());
        Assert.assertEquals(Float.class, parameterType.getGeneric(1, 0).resolve());
        Assert.assertEquals(Integer.class, parameterType.getGeneric(1, 1).resolve());
    }
    

    (4) 其它常用方法

    @Test
    public void test() {
        // HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
        ResolvableType resolvableType = ResolvableType.forClass(HashMap.class);
        // 1. getInterfaces 获取接口
        Assert.assertEquals(Map.class, resolvableType.getInterfaces()[0].resolve());
    
        // 2. getSuperType 获取父类
        Assert.assertEquals(AbstractMap.class, resolvableType.getSuperType().resolve());
    
        // 3. as 向上转型 Map<K,V>
        ResolvableType mapResolvableType = resolvableType.as(Map.class);
        Assert.assertEquals(Map.class, mapResolvableType.resolve());
        // 4. getRawClass 当 type 是 ParameterizedType 时有效
        Assert.assertEquals(Map.class, mapResolvableType.getRawClass());
        Assert.assertEquals(HashMap.class.getGenericInterfaces()[0], mapResolvableType.getType());
    
        // 5. getGeneric 获取泛型 class ServiceImpl<A, B> implements Service<String, Integer>
        resolvableType = ResolvableType.forClass(ServiceImpl.class);
        // 当 Type 无法找到具体的 class 类型时返回 null
        Assert.assertEquals("A", resolvableType.getGeneric(0).getType().getTypeName());
        Assert.assertEquals(null, resolvableType.getGeneric(0).resolve());
        // 以下两种获取泛型的 Class 类型方式等价
        Assert.assertEquals(String.class, resolvableType.as(Service.class).getGeneric(0).resolve());
        Assert.assertEquals(String.class, resolvableType.as(Service.class).resolveGeneric(0));
    
        // 5. getComponentType 获取数组泛型 List<String>[] array
        resolvableType = ResolvableType.forField(
                ReflectionUtils.findField(ResolveTypeTest.class, "array"));
        Assert.assertEquals(List.class, resolvableType.getComponentType().resolve());
    }
    

    (5) 创建 ResolvableType

    @Test
    public void test() {
        ResolvableType resolvableType1 = ResolvableType.forClassWithGenerics(List.class, String.class);
        ResolvableType resolvableType2 = ResolvableType.forArrayComponent(resolvableType1);
        resolvableType2.getComponentType().getGeneric(0).resolve();
    
        // List<String>[] array
        ResolvableType resolvableType3 = ResolvableType.forField(
                ReflectionUtils.findField(ResolveTypeTest.class, "array"));
        Assert.assertTrue(resolvableType3.isAssignableFrom(resolvableType2));
    
        Assert.assertTrue(ResolvableType.forClass(Object.class).isAssignableFrom(
                ResolvableType.forClass(String.class)));
    }
    

    通过使用也可以看出 ResolvableType 最主要的目的是解析传入的 Type 类型,并通过 resolve() 获取真实的 Class 类型。

    二、ResolvalbeType 源码分析

    (1) ResolvalbeType 重要属性

    // 需要解析的 JDK Type 类型
    private final Type type;
    // 缓存解析后的 Class 类型
    private Class<?> resolved;
    
    // 缓存解析后父类、接口、泛型、数组泛型等
    private volatile ResolvableType superType;
    private volatile ResolvableType[] interfaces;
    private volatile ResolvableType[] generics;
    private final ResolvableType componentType;
    

    另外还有两个工具类辅助解析用:

    // 对 Type 进行封装
    private final TypeProvider typeProvider;
    // 对 TypeVariable 如何解析为 Class 的策略
    private final VariableResolver variableResolver;
    

    (2) forField

    下面以 forField(Field field) 为例,看 ResolvalbeType 是如何解析泛型的。

    public static ResolvableType forField(Field field) {
        Assert.notNull(field, "Field must not be null");
        return forType(null, new FieldTypeProvider(field), null);
    }
    
    static ResolvableType forType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) {
        if (type == null && typeProvider != null) {
            type = SerializableTypeWrapper.forTypeProvider(typeProvider);
        }
        if (type == null) {
            return NONE;
        }
    
        // 1. Class 不用解析,所以没必要不缓存
        if (type instanceof Class) {
            return new ResolvableType(type, typeProvider, variableResolver, (ResolvableType) null);
        }
        cache.purgeUnreferencedEntries();
    
        // 2. 其余的 Type 类型需要解析,所以先缓存起来
        // 2.1 这个构造器专为缓存使用,不会触发 resolveClass() 操作
        ResolvableType resultType = new ResolvableType(type, typeProvider, variableResolver);
        ResolvableType cachedType = cache.get(resultType);
        if (cachedType == null) {
            // 2.2 如果缓存中没有就需要解析了,这个构造器会触发 resolveClass() 操作
            cachedType = new ResolvableType(type, typeProvider, variableResolver, resultType.hash);
            cache.put(cachedType, cachedType);
        }
        resultType.resolved = cachedType.resolved;
        return resultType;
    }
    

    解析 Type 对应的真实 Class 类型在 cachedType = new ResolvableType(type, typeProvider, variableResolver, resultType.hash) 这一步,会触发 resolveClass() 操作。

    private ResolvableType(Type type, @Nullable TypeProvider typeProvider,
            @Nullable VariableResolver variableResolver, @Nullable Integer hash) {
        this.type = type;
        this.typeProvider = typeProvider;
        this.variableResolver = variableResolver;
        this.componentType = null;
        this.hash = hash;
        this.resolved = resolveClass(); // 关键
    }
    

    (3) resolveClass

    resolveClass() 方法先对两种简单的类型 Class 和 GenericArrayType 进行了解析,其余的 Type 类型则委托给了 resolveType() 方法解析。

    private Class<?> resolveClass() {
        if (this.type == EmptyType.INSTANCE) {
            return null;
        }
        // 1. Class 类型
        if (this.type instanceof Class) {
            return (Class<?>) this.type;
        }
        // 2. GenericArrayType 泛型数组,成员变量的 Class 类型
        if (this.type instanceof GenericArrayType) {
            Class<?> resolvedComponent = getComponentType().resolve();
            return (resolvedComponent != null ? Array.newInstance(resolvedComponent, 0).getClass() : null);
        }
        return resolveType().resolve();
    }
    

    对于 Class 和 GenericArrayType 两种 Type 类型:

    • Class 解析后仍为该 Class 类型
    • GenericArrayType 该泛型数组成员变量的 Class 类型

    (4) resolveType

    剩余的 ParameterizedType、WildcardType、TypeVariable 三种类型继续解析。

    ResolvableType resolveType() {
        // 3. ParameterizedType 类型,getRawType 的 Class 类型
        if (this.type instanceof ParameterizedType) {
            return forType(((ParameterizedType) this.type).getRawType(), this.variableResolver);
        }
        // 4. WildcardType 类型,上界或下界的 Class 类型,如有多个只取第一个
        if (this.type instanceof WildcardType) {
            Type resolved = resolveBounds(((WildcardType) this.type).getUpperBounds());
            if (resolved == null) {
                resolved = resolveBounds(((WildcardType) this.type).getLowerBounds());
            }
            return forType(resolved, this.variableResolver);
        }
        // 5. TypeVariable 类型
        if (this.type instanceof TypeVariable) {
            TypeVariable<?> variable = (TypeVariable<?>) this.type;
            // 5.1 使用 resolveVariable 解析 Try default variable resolution
            if (this.variableResolver != null) {
                ResolvableType resolved = this.variableResolver.resolveVariable(variable);
                if (resolved != null) {
                    return resolved;
                }
            }
            // 5.2 TypeVariable 默认取上界的 Class 类型,如有多个只取第一个
            return forType(resolveBounds(variable.getBounds()), this.variableResolver);
        }
        return NONE;
    }
    

    resolveType对于 ParameterizedType、WildcardType、TypeVariable 三种 Type 类型:

    • ParameterizedType getRawType 对应的 Class 类型
    • WildcardType 上界或下界的 Class 类型,如有多个只取第一个
    • TypeVariable 默认取上界的 Class 类型,如有多个只取第一个,也可以是 variableResolver 解析,默认为 DefaultVariableResolver

    (5) getGenerics

    public ResolvableType[] getGenerics() {
        if (this == NONE) {
            return EMPTY_TYPES_ARRAY;
        }
        ResolvableType[] generics = this.generics;
        if (generics == null) {
            // 1. 获取 Class 类型的泛型
            if (this.type instanceof Class) {
                Type[] typeParams = ((Class<?>) this.type).getTypeParameters();
                generics = new ResolvableType[typeParams.length];
                for (int i = 0; i < generics.length; i++) {
                    generics[i] = ResolvableType.forType(typeParams[i], this);
                }
            // 2. 获取 ParameterizedType 类型的泛型
            } else if (this.type instanceof ParameterizedType) {
                Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments();
                generics = new ResolvableType[actualTypeArguments.length];
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    generics[i] = forType(actualTypeArguments[i], this.variableResolver);
                }
            // 3. WildcardType、TypeVariable 类型调用 resolveType() 重新解析
            } else {
                generics = resolveType().getGenerics();
            }
            this.generics = generics;
        }
        return generics;
    }
    

    参考:

    1. 《Spring ResolvableType 更好的处理泛型》:https://blog.csdn.net/u012881904/article/details/80813294

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    web标准化布局
    最全前端资源汇集
    SVN使用教程
    FullPage.js中文帮助文档API
    如何选字体(font-family)
    网站禁止复制类型的属性
    Web前端学习方向
    div 命名规范! (野路子出来的好好看看)
    浏览器兼容处理
    JSONP 跨域问题
  • 原文地址:https://www.cnblogs.com/binarylei/p/10344262.html
Copyright © 2011-2022 走看看