ResolvableType
在学习了Java的Type体系后,我们会发现,依赖于整个Type体系去处理泛型代码非常的繁琐,并且不易于理解。基于这种情况,Spring开发了一个ResolvableType类,这个类对整个Type体系做了系统的封装。
实际上关于ResolvableType的学习大家可以参数Spring中的org.springframework.core.ResolvableTypeTests类,这是作者写好的单元测试类,覆盖了ResolvableType的所有方法。
这个类的代码量很大,不过我们也没有必要去详细地看每一行代码,粗略阅读源码后会发现这个类有以下几个特点
概览
1.所有的构造函数都是私有的
在上图中那把小锁代表权限为private,就是私有的意思
构造函数都是在为相同的成员变量赋值,这里我随便放一个构造函数如下
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,如下:
所有for开头的方法都是静态方法,同时都能获取一个ResolvableType,现在对常见的几个方法进行分析:
方法分析
forClass系列方法
Spring中经常会用到一个方法,ResolvableType.forRawClass(type),我们就先看下这一系列的三个方法
- ResolvableType.forRawClass(type)
- ResolvableType forClass(@Nullable Class<?> clazz)
- ResolvableType forClass(Class<?> baseType, Class<?> implementationClass)
- ResolvableType forClassWithGenerics(Class<?> clazz, Class<?>… generics)
- ResolvableType forClassWithGenerics(Class<?> clazz, ResolvableType… generics)
forRawClass(Class<?> clazz)
public static ResolvableType forRawClass(@Nullable Class<?> clazz) { return new ResolvableType(clazz) { @Override public ResolvableType[] getGenerics() { return EMPTY_TYPES_ARRAY; } @Override public boolean isAssignableFrom(Class<?> other) { return (clazz == null || ClassUtils.isAssignable(clazz, other)); } @Override public boolean isAssignableFrom(ResolvableType other) { Class<?> otherClass = other.getRawClass(); return (otherClass != null && (clazz == null || ClassUtils.isAssignable(clazz, otherClass))); } }; }
这个方法实际上做了两件事
1.用了构造函数,private ResolvableType(@Nullable Class<?> clazz)
2.复写了三个方法
对比另外一个方法
forClass(Class<?> clazz)
public static ResolvableType forClass(@Nullable Class<?> clazz) { return new ResolvableType(clazz); }
对比后可以发现,这两个方法唯一的区别就是没有复写其中的三个方法。大家可以思考下,这是为什么呢?
其实区别在于,对于第一个forRawClass方法,入参传入的一定是一个原始数据类型,也就是一个不带泛型的类的Class对象,比如传入的可能是一个Person.class,Dog.class。对于这种原始数据类型,其getGenerics,isAssignableFrom方法的实现逻辑是固定的,所以forRawClass方法直接对这三个方法进行了复写。
forClass(Class<?> baseType, Class<?> implementationClass)
public static ResolvableType forClass(Class<?> baseType, Class<?> implementationClass) { Assert.notNull(baseType, "Base type must not be null"); // as方法在之后分析,就是根据继承链找打对应的父类 ResolvableType asType = forType(implementationClass).as(baseType); return (asType == NONE ? forType(baseType) : asType); }
implementationClass是baseType的子类,这个方法主要获取baseType上定义的泛型,例如:
public class ResolvableTypeDemo { public static void main(String[] args) { // 获取到C继承的HashMap所构建的一个ResolvableType,会带用泛型<String, Integer> ResolvableType resolvableType = ResolvableType.forClass(HashMap.class, C.class); ResolvableType[] generics = resolvableType.getGenerics(); for (ResolvableType generic : generics) { // 程序打印: // class java.lang.String // class java.lang.Integer System.out.println(generic.getType()); } } } class C extends HashMap<String, Integer> { }
forConstructor系列方法
public static ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex, Class<?> implementationClass) { Assert.notNull(constructor, "Constructor must not be null"); MethodParameter methodParameter = new MethodParameter(constructor, parameterIndex); methodParameter.setContainingClass(implementationClass); return forMethodParameter(methodParameter); } public static ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex) { Assert.notNull(constructor, "Constructor must not be null"); return forMethodParameter(new MethodParameter(constructor, parameterIndex)); }
可以看到,forConstructor系列方法最后都调用了forMethod系列方法,我们直接分析forMethod系列的方法
forMethod系列方法
主要分为两类方法
1.forMethodParameter,解决方法参数上的类型问题
2.forMethodReturnType,解决方法返回值的类型问题
forMethodParameter
public class ResolvableTypeDemo { public void test(List<String> list, Map<String, List<Integer>> map) { } public static void main(String[] args) throws Exception { Class<ResolvableTypeDemo> resolvableTypeDemoClass = ResolvableTypeDemo.class; Method[] declaredMethods = resolvableTypeDemoClass.getDeclaredMethods(); Method test = declaredMethods[1]; // 获取方法的第一个参数对应的ResolvableType,参数为-1代表返回值,0为第一个,1为第二个,一次增加 ResolvableType resolvableType0 = ResolvableType.forMethodParameter(test, 0); System.out.println(resolvableType0.resolve()); System.out.println(resolvableType0.getType()); // 获取方法的第二个参数对应的ResolvableType ResolvableType resolvableType1 = ResolvableType.forMethodParameter(test, 1); System.out.println(resolvableType1.resolve()); System.out.println(resolvableType1.getType()); } }
forMethodReturnType
public static ResolvableType forMethodReturnType(Method method) { Assert.notNull(method, "Method must not be null"); return forMethodParameter(new MethodParameter(method, -1)); }
调用逻辑很简单,调用forMethodParameter,并将方法的参数索引替换为-1,代表返回值
forConstructor系列方法
构造函数就是一个特殊的方法,所以都是直接调用的forMethod系列方法,这里就不多介绍了
forField系列方法
专门用于处理字段的类型,如下:
测试方法Demo
public class ResolvableTypeDemo { List<String> stringList; List<List<String>> lists; public static void main(String[] args) throws Exception { Class<ResolvableTypeDemo> resolvableTypeDemoClass = ResolvableTypeDemo.class; Field[] declaredFields = resolvableTypeDemoClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("=======字段名称"+declaredField.getName()+"========="); System.out.println("nestingLevel为1"); ResolvableType resolvableType1 = ResolvableType.forField(declaredField,1); System.out.println(resolvableType1.getType()); System.out.println(resolvableType1.resolve()); System.out.println("nestingLevel为2"); ResolvableType resolvableType2 = ResolvableType.forField(declaredField,2); System.out.println(resolvableType2.getType()); System.out.println(resolvableType2.resolve()); System.out.println("nestingLevel为3"); ResolvableType resolvableType3 = ResolvableType.forField(declaredField,3); System.out.println(resolvableType3.getType()); System.out.println(resolvableType3.resolve()); } } }
程序打印:
=======字段名称stringList========= nestingLevel为1 java.util.List<java.lang.String> interface java.util.List nestingLevel为2 class java.lang.String class java.lang.String nestingLevel为3 org.springframework.core.ResolvableType$EmptyType@723279cf null =======字段名称lists========= nestingLevel为1 java.util.List<java.util.List<java.lang.String>> interface java.util.List nestingLevel为2 java.util.List<java.lang.String> interface java.util.List nestingLevel为3 class java.lang.String class java.lang.String
在上面的所有方法,最后都会调用一个forType方法,所以我们着重也就分析这个系列的方法
forType系列(源码分析)
最终都会调用到这个方法中,源码如下:
static ResolvableType forType( @Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) { // 这里可以看出,即使我们提供了一个typeProvider,也不会直接调用它的getType返回,而是会进行一层包装,这个是为什么呢?我们稍后分析 if (type == null && typeProvider != null) { type = SerializableTypeWrapper.forTypeProvider(typeProvider); } if (type == null) { // 自身定义的一个常量,ResolvableType NONE = new ResolvableType(EmptyType.INSTANCE, null, null, 0); return NONE; } // 如果是原始的数据类型(一个简单的Class引用),那么直接封装后返回,这里不做缓存,因为没有上面昂贵的开销 if (type instanceof Class) { return new ResolvableType(type, typeProvider, variableResolver, (ResolvableType) null); } // 省略缓存相关的代码。。。 return resultType; }
上面这段代码比较核心的就是SerializableTypeWrapper.forTypeProvider(typeProvider),我之前也提到了一个问题,为什么要多包装一层呢?这么做的目的主要就是为了得到一个可以进行序列化的Type。
它的核心代码如下:
static Type forTypeProvider(TypeProvider provider) { // 直接从provider获取到具体的类型 Type providedType = provider.getType(); if (providedType == null || providedType instanceof Serializable) { // 如果本身可以序列化的直接返回,例如Java.lang.Class。 // 如果不能进行序列化,多进行一层包装 return providedType; } // 不用管这段代码,我们开发过程中必定不成立 if (GraalDetector.inImageCode() || !Serializable.class.isAssignableFrom(Class.class)) { return providedType; } // 从缓存中获取 Type cached = cache.get(providedType); if (cached != null) { return cached; } // 遍历支持的集合,就是GenericArrayType.class, ParameterizedType.class, TypeVariable.class, WildcardType.class,处理这个四种类型 for (Class<?> type : SUPPORTED_SERIALIZABLE_TYPES) { if (type.isInstance(providedType)) { ClassLoader classLoader = provider.getClass().getClassLoader(); // 创建的代理类实现的接口,type就不用说了代理类跟目标类必须是同一个类型 // SerializableTypeProxy:标记接口,标志是一个代理类 // Serializable:代表可以被序列化 Class<?>[] interfaces = new Class<?>[] {type, SerializableTypeProxy.class, Serializable.class}; // 核心代码:TypeProxyInvocationHandler是什么? InvocationHandler handler = new TypeProxyInvocationHandler(provider); // 依赖于先前的InvocationHandler,以当前的type为目标对象创建了一个代理对象 // cached = (Type) Proxy.newProxyInstance(classLoader, interfaces, handler); cache.put(providedType, cached); return cached; } } throw new IllegalArgumentException("Unsupported Type class: " + providedType.getClass().getName()); }
解析来我们分下下TypeProxyInvocationHandler这个类
private static class TypeProxyInvocationHandler implements InvocationHandler, Serializable { private final TypeProvider provider; public TypeProxyInvocationHandler(TypeProvider provider) { this.provider = provider; } @Override @Nullable public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // 复写目标类的equals方法 if (method.getName().equals("equals") && args != null) { Object other = args[0]; // Unwrap proxies for speed if (other instanceof Type) { other = unwrap((Type) other); } return ObjectUtils.nullSafeEquals(this.provider.getType(), other); } // 复写目标类的hashCode方法 else if (method.getName().equals("hashCode")) { return ObjectUtils.nullSafeHashCode(this.provider.getType()); } // 复写目标类的getTypeProvider方法 else if (method.getName().equals("getTypeProvider")) { return this.provider; } // 之所以不直接返回method.invoke(this.provider.getType(), args);也是为了缓存 // 空参的时候才能缓存,带参数的话不能缓存,因为每次调用传入的参数可能不一样 if (Type.class == method.getReturnType() && args == null) { return forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, -1)); } else if (Type[].class == method.getReturnType() && args == null) { Type[] result = new Type[((Type[]) method.invoke(this.provider.getType())).length]; for (int i = 0; i < result.length; i++) { result[i] = forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, i)); } return result; } try { return method.invoke(this.provider.getType(), args); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }
总结
在这篇文章中我们主要学习了java的Type机制,如下:
Type主要是用来处理泛型的,但是通过Java原始的这一套,处理起来及其的繁琐,所以Spring自行封装了一个ResolvableType,我们在处理类,方法,构造函数,字段时,只需要调用对应的方法就能返回一个对应的ResolvableType,一个ResolvableType就封装了对应的这个对象的原始类型,泛型等等,封装了Java中的所有类型。从这里也能看出Spring的牛逼之处,处理提供了IOC,AOP这两个强大的功能,还封装了一系列的简单易用的工具类。