Spring中基于泛型类型的自动装配是如何工作的?

12

正如您所知,Spring 4 中有一个新功能:基于通用类型的自动装配。

这是非常有用的,但我想知道,Spring 的开发人员是如何绕过类型擦除的,这曾经阻止他们开发这样的功能。

(注意:保留了原文中的 标签)


1
根据http://spring.io/blog/2013/12/03/spring-framework-4-0-and-java-generics,这是黑魔法 :D - EpicPandaForce
1
这里没有黑魔法,只有对内置的JDK反射类的一堆调用。在ResolvableType的背后组织这些调用并不会添加魔法。专业提示:编程中没有所谓的黑魔法,只有你还没读过的代码。 - yshavit
2个回答

12

擦除意味着信息从运行时中消失。它仍然存在于编译时的信息中,您可以通过反射访问它。在粗略的级别上,您可以认为有关个别实例的通用信息已被删除,但有关的通用信息并未被删除。

例如,这里有一个简单的程序,定义了一个泛型方法foo,然后从main中打印出有关它的泛型信息:

import java.util.*;
import java.lang.reflect.*;

public class GenericReflection {
  public static void main(String[] args) throws Exception {
    Method m = GenericReflection.class.getDeclaredMethod("foo");
    System.out.println(m.getGenericReturnType());
  }

  public static List<String> foo() {
    return null;
  }
}

输出:

java.util.List<java.lang.String>

正如您所看到的,一旦深入了解,它并不太复杂。

Method.getGenericReturnType 返回一个 java.lang.reflect.Type,它有一些子类。其中之一是 ParameterizedType,它有一个方法 getActualTypeArguments,返回此类型参数化的实际类型。当然,这些类型也可能是泛型的,这就是为什么它返回一个 Type[] 而不是 Class[] 的原因。在上面的 foo 示例中,它将返回一个具有一个元素的数组,表示 String

ParameterizedType pm = (ParameterizedType) m.getGenericReturnType();
Type[] pmArgs = pm.getActualTypeArguments();
System.out.println(Arrays.toString(pmArgs));

[class java.lang.String]

类似的“通用”方法也适用于Field.getGenericType。您可以使用此信息了解List<String>是参数化为StringList,这正是他们需要的信息。


但是Spring在运行时决定注入哪个类的对象。那么当有两个相同的类(由于类型擦除而使用Object代替泛型类型)但名称不同时,框架如何处理呢?它是否使用类型转换?还是我完全误解了情况? :) - Patison
如果你注意到了,我也是在运行时完成的。我会进行编辑,使其更加明确。 - yshavit
好像我明白了...所以,在类文件的某个元数据中存储了所有类型,类型擦除实际上并不完全清除,他们的“ResolvableType”包含超过一千行,只调用JDK的“ParameterizedType”的getActualTypeArguments() - Patison
是的。如果您查看ResolvableType的代码,您会发现大部分代码只是“助手”代码,用于在给定Type(以及一些其他东西,但基本上只是这样)的情况下回答特定问题。它实际上甚至不直接调用getActualTyoeArguments:它提供了助手来导航类型信息(例如获取嵌套类型),然后提供了一个getType()方法来提供底层Type。 - yshavit
1
我并没有深入阅读过ResolvableType,也没有使用过它...但通常是这样做的。我的回答的主要目的是说明擦除并不意味着从类元数据中抹去所有信息。 - yshavit

4

最重要的细节在this Spring Blog文章中。

正如您所看到的,所有魔法都隐藏在ResolvableType类中,您可以在此处找到其Javadochere,其代码可以在此处找到here(这是一篇相当深奥的阅读 :))


谢谢,我看了这个博客页面,但是不太明白它是如何工作的。如果您知道的话,能否简单地解释一下呢? :) - Patison
我之前看过它,但我不能说我真的记得那里发生了什么。看来我们需要亲自动手去阅读它!顺便说一句,这是个很棒的问题! - geoand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接