Spring 元件(一)Spring 是如何解析泛型 - ResolvalbeType
Spring 元件(一)Spring 是如何解析泛型 - ResolvalbeType
Spring 系列目錄(https://www.cnblogs.com/binarylei/p/10117436.html)
Java Type 泛型系列文章:
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;
}
參考:
- 《Spring ResolvableType 更好的處理泛型》:https://blog.csdn.net/u012881904/article/details/80813294
每天用心記錄一點點。內容也許不重要,但習慣很重要!