Spring中如何理解并运用ResolvableType的泛型处理
前言
泛型自 Java 5 诞生,为了支持泛型,Java 5 新增了 Type 类,表示 Java 中的某一种类型,反射包中提供的获取泛型类型的方法中多是返回 Type 类型,使用时需要进行强制类型转换,为了简化对泛型信息的获取,Spring 4 开始提供了一个 ResolvableType,本篇将详细对其分析。
ResolvableType 的使用场景
假定有下面的类
public class GenericClazz { private HashMap<String, List<Integer>> param; }
为了获取泛型类型的成员变量的泛型相关信息,使用 JDK 提供的方法如下,参见 学习 Java,你不得不知的泛型知识。
public class GenericClazz { private HashMap<String, List<Integer>> param; public static void main(String[] args) throws NoSuchFieldException { printParamByJdk(); } public static void printParamByJdk() throws NoSuchFieldException { Field param = GenericClazz.class.getDeclaredField("param"); Type genericType = param.getGenericType(); ParameterizedType type = (ParameterizedType) genericType; Type[] typeArguments = type.getActualTypeArguments(); System.out.println("从 HashMap<String, List<Integer>> 中获取 String:" + typeArguments[0]); System.out.println("从 HashMap<String, List<Integer>> 中获取 List<Integer> :" + typeArguments[1]); System.out.println( "从 HashMap<String, List<Integer>> 中获取 List :" + ((ParameterizedType) typeArguments[1]).getRawType()); System.out.println("从 HashMap<String, List<Integer>> 中获取 Integer:" + ((ParameterizedType) typeArguments[1]) .getActualTypeArguments()[0]); System.out.println("从 HashMap<String, List<Integer>> 中获取父类型:"+param.getType().getGenericSuperclass()); } }
打印结果如下。
从 HashMap<String, List<Integer>> 中获取 String:class java.lang.String 从 HashMap<String, List<Integer>> 中获取 List<Integer> :java.util.List<java.lang.Integer> 从 HashMap<String, List<Integer>> 中获取 List :interface java.util.List 从 HashMap<String, List<Integer>> 中获取 Integer:class java.lang.Integer 从 HashMap<String, List<Integer>> 中获取父类型:java.util.AbstractMap<K, V>
JDK 提供的方法已经相对比较简洁,Spring ResolvableType 对其进一步抽象,使用 ResolvableType 后解析上述泛型信息的代码如下。
public class GenericClazz { private HashMap<String, List<Integer>> param; public static void main(String[] args) throws NoSuchFieldException { printParmaBySpring(); } private static void printParmaBySpring() throws NoSuchFieldException { ResolvableType param = ResolvableType.forField(GenericClazz.class.getDeclaredField("param")); System.out.println("从 HashMap<String, List<Integer>> 中获取 String:" + param.getGeneric(0).resolve()); System.out.println("从 HashMap<String, List<Integer>> 中获取 List<Integer> :" + param.getGeneric(1)); System.out.println( "从 HashMap<String, List<Integer>> 中获取 List :" + param.getGeneric(1).resolve()); System.out.println("从 HashMap<String, List<Integer>> 中获取 Integer:" + param.getGeneric(1,0)); System.out.println("从 HashMap<String, List<Integer>> 中获取父类型:" +param.getSuperType()); } }
打印结果如下。
从 HashMap<String, List<Integer>> 中获取 String:class java.lang.String 从 HashMap<String, List<Integer>> 中获取 List<Integer> :java.util.List<java.lang.Integer> 从 HashMap<String, List<Integer>> 中获取 List :interface java.util.List 从 HashMap<String, List<Integer>> 中获取 Integer:java.lang.Integer 从 HashMap<String, List<Integer>> 中获取父类型:java.util.AbstractMap<java.lang.String, java.util.List<java.lang.Integer>>
可以看到泛型类可以使用 ResolvableType 类统一表示,泛型类型信息都可以通过 ResolvableType 中的方法直接获取,而不必再额外调用其他类的方法,获取父类型信息的时候,ResolvableType 还友好的获取到了父类型中的实际类型,ResolvableType 提供的能力远不止如此。
Spring 中对 ResolvableType 的使用,事件处理是一个典型的代表,Spring 事件监听器的定义如下。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { // 处理应用的事件 void onApplicationEvent(E event); }
事件监听器监听的事件是一个泛型类型,应用可以向 Spring 中注入任意 ApplicationListener 类型的 bean,当发送事件时,Spring 知道如何根据具体的事件类型选择合适的事件监听器处理事件,关于 Spring 事件处理,将在后面的文章中详细介绍。下面先看 ResolvableType 提供了哪些能力。
ResolvableType 提供了哪些能力
如何创建 ResolvableType
使用 ResolvableType,需要先获取其实例,泛型类型可以存在于类、成员变量、构造器参数、成员方法参数、方法返回值,对应于这些泛型类型可以存在的位置,ResolvableType 提供了一些将这些泛型类型信息转换为 ResolvableType 的静态方法,常见的方法如下。
public class ResolvableType implements Serializable { // 根据原始类型 Class 创建 ResolvableType public static ResolvableType forClass(@Nullable Class<?> clazz); // 根据构造器参数创建 ResolvableType public static ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex); // 根据成员变量创建 ResolvableType public static ResolvableType forField(Field field); // 根据实例创建 ResolvableType public static ResolvableType forInstance(Object instance); // 根据方法参数创建 ResolvableType public static ResolvableType forMethodParameter(Method method, int parameterIndex); // 根据方法的返回值创建 ResolvableType public static ResolvableType forMethodReturnType(Method method); // 根据原始类型信息创建 ResolvableType public static ResolvableType forRawClass(@Nullable Class<?> clazz); // 根据某一种类型创建 ResolvableType public static ResolvableType forType(@Nullable Type type); }
如何根据 ResolvableType 获取泛型信息
ResolvableType 定义了一些方法可以用于获取泛型信息,具体如下。
public class ResolvableType implements Serializable { // 获取泛型数组的元素类型 public ResolvableType getComponentType(); // 获取泛型的实际类型,索引位置从0开始 // 如取 HashMap<String, List<Integer>> 中的 Integer,参数可以为 {1,0} public ResolvableType getGeneric(@Nullable int... indexes); public ResolvableType[] getGenerics(); // 获取类型的接口 public ResolvableType[] getInterfaces(); // 获取指定嵌套级别的 类型,嵌套级别从 1 开始 // 如取 HashMap<String, List<Integer>> 中的 List<Integer> 参数可取 1,{2:1} public ResolvableType getNested(int nestingLevel); public ResolvableType getNested(int nestingLevel, @Nullable Map<Integer, Integer> typeIndexesPerLevel); // 获取原始类型 public Class<?> getRawClass(); // 获取父类型 public ResolvableType getSuperType(); // 获取当前实例表示的类型 public Type getType(); // 当前实例是否包含泛型参数 public boolean hasGenerics(); // 当前实例是否为数组 public boolean isArray(); // 当前实例是否为给定参数的类型或父类型 public boolean isAssignableFrom(Class<?> other); public boolean isAssignableFrom(ResolvableType other); // 获取当前实例解析出的类 public Class<?> resolve(); public Class<?> resolveGeneric(int... indexes) }
ResolvableType 实现分析
对于一个类,行为围绕其状态展开,因此确认好类中保存的成员变量,然后再有目的的对方法进行分析即可,下面对 ResolvableType#getGeneric 方法进行分析,了解其实现后即可理解 ResolvableType 中大多数方法的实现。
ResolvableType 对外暴露的方法除了用于实例化自身的静态工厂方法,其他的多数都为实例方法。以ResolvableType#forField(Field) 方法作为入口,其代码如下。
public static ResolvableType forField(Field field) { Assert.notNull(field, "Field must not be null"); return forType(null, new FieldTypeProvider(field), null); }
这个方法只是简单的调用了方法 forType
,源码如下。
/** * 返回由给定的可解析类型变量解析器. * @param type 源类型 * @param typeProvider 类型提供者 * @param variableResolver 类型变量解析器,可以将类型变量解析为 ResolvableType * @return 指定类型和类型变量解析器对应的 ResolvableType */ static ResolvableType forType( @Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) { if (type == null && typeProvider != null) { // 未直接指定类型,根据 TypeProvider 获取类型 type = SerializableTypeWrapper.forTypeProvider(typeProvider); } if (type == null) { return NONE; } if (type instanceof Class) { // Class 类型直接实例化 return new ResolvableType(type, typeProvider, variableResolver, (ResolvableType) null); } cache.purgeUnreferencedEntries(); // 其他类型实例化后进行缓存 ResolvableType resultType = new ResolvableType(type, typeProvider, variableResolver); ResolvableType cachedType = cache.get(resultType); if (cachedType == null) { cachedType = new ResolvableType(type, typeProvider, variableResolver, resultType.hash); cache.put(cachedType, cachedType); } resultType.resolved = cachedType.resolved; return resultType; }
forType 方法先获取类型,然后判断类型如果为 Class 直接调用构造方法实例化,否则实例化后还会进行缓存。直接实例化的构造方法如下。
private ResolvableType(Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver, @Nullable ResolvableType componentType) { this.type = type; this.typeProvider = typeProvider; this.variableResolver = variableResolver; this.componentType = componentType; this.hash = null; this.resolved = resolveClass(); }
ResolvableType 的构造方法都为私有方法,因此只能根据静态工厂方法获取 ResolvableType 类型的实例,构造方法简单的把参数赋值到成员变量,下面看 ResolvableType 中有哪些成员变量。