Spring 是如何解析泛型 - ResolvalbeType

Spring 是如何解析泛型 - ResolvalbeType

Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html

Java Type 泛型系列文章:java

  1. Java - Type 介紹
  2. Java - Type 的獲取方式
  3. Spring - ResolvableType

Spring 中大量使用反射,須要獲取泛型的具體類型,爲此專門提供了一個工具類解析泛型 - ResolvalbeType。ResolvableType 是對 Class,Field,Method 獲取 Type 的抽象。spring

1、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) forMethodParameterapp

forMethodParameter 還有不少變種:如 forConstructorParameter、forMethodReturnTypeide

@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 類型。this

2、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

天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索