为任何T

时间:2015-08-11 14:27:47

标签: java spring

因此,我有一些使用反射来初始化自己的通用组件,通过这样做,它们在实例化时需要Class<T>个对象。这些组件使用注释来生成有用的元数据和/或将对象转换为更适合手头任务的另一种表示。

我将问题简化为此示例组件:

@Component
public class Instantiator<T> {
    final Class<T> klass;

    @Autowired
    public Instantiator(Class<T> klass) {
        this.klass = klass;
    }

    public T instantiate() {
        try {
            return klass.newInstance();
        } catch (InstantiationException|IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

Spring不知道如何自动注入Class<T>个实例,因此我尝试为每个T编写以下样板代码,我希望Class<T>可用。{/ p>

@Bean
Class<Instantiatee> instantiateeClass() {
    return Instanciatee.class;
}

它不起作用。

Spring版本4支持自动装配泛型类型,但在我的情况下,它必须推断T中分配了Class<T>的内容。因为默认情况下Spring会创建单例bean,因此无法推断出合适的T,我尝试添加@Scope("prototype")但我最终得到ClassCastException,因为容器不知道如何推断{ {1}}无论如何。

因此,我从Instantiator中删除了T注释,并针对我拥有的每个@Component确定了此解决方法:

T

您是否知道一项解决方法,以便在每次我需要@Bean Instantiator<Instantiatee> instantiator() { return new Instantiator<>(Instantiatee.class); } 或其他通用组件时根据它来推断T

仅供参考,我们正在使用spring 4.1.4 with boot。

我在那里发布了一个更完整的示例:https://gist.github.com/anonymous/79e1a7ebe7c25c00a6c2

1 个答案:

答案 0 :(得分:0)

使用/((?: |^)\w+){2}<\/em><em>(\w+(?: |$)){2}/gm 定义bean,默认情况下,在方法名称中提供bean名称 - 在您的情况下为@Bean。此外,在自动装配时,默认bean名称被视为参数名称,在您的情况下为getInstanciateeClass。因此,Spring无法匹配bean,因为它们具有不同的名称,并且很可能klass中有多个Class个实例。如果一个是ApplicationContext而另一个是Class<Foo>并不重要,Spring会将它们视为Class<Bar>,因此它无法按类型进行自动装配。

您可以在定义bean和自动装配时使用相同的默认名称来解决此问题。

Class

您还可以在@Bean注释中指定bean的名称:

@Autowired
public Instanciator(Class<T> klass) {
    this.klass = klass;
}

@Bean
Class<Instanciatee> klass() {
    return Instanciatee.class;
}

或者您也可以在自动装配时给出bean名称:

@Autowired
public Instanciator(Class<T> klass) {
    this.klass = klass;
}

@Bean(name = "klass")
Class<Instanciatee> getInstanciateeClass() {
    return Instanciatee.class;
}