因此,我有一些使用反射来初始化自己的通用组件,通过这样做,它们在实例化时需要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。
答案 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;
}