Spring中能否注入某类型所有子类的Class对象列表?
解决Spring注入子类Class对象列表的问题
问题原因
你当前的代码试图注入List<Class<? extends StringProvider>>,但Spring容器中注册的是StringProvider类型的实例Bean,而非Class类型的Bean。Spring找不到匹配类型的Bean,因此抛出NoSuchBeanDefinitionException。
解决方案
方案1:从已实例化的Bean中提取Class对象
先注入所有StringProvider类型的Bean实例,再从中提取对应的Class。这种方式简单直接,适用于Bean已经实例化的场景:
@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = GenericTest.Config.class) public class GenericTest { // 先注入所有StringProvider实例 @Autowired private List<StringProvider> stringProviderBeans; private List<Class<? extends StringProvider>> stringProviderClasses; @PostConstruct public void init() { // 从实例中提取Class并去重,处理AOP代理获取真实目标类 stringProviderClasses = stringProviderBeans.stream() .map(AopProxyUtils::ultimateTargetClass) .distinct() .collect(Collectors.toList()); } @Test void test() { // 现在可以使用stringProviderClasses调用静态方法 stringProviderClasses.forEach(clazz -> System.out.println(clazz.getName())); } interface StringProvider { String getString(); } @Configuration static class Config { @Bean public StringProvider stringProviderOne() { return () -> "one"; } @Bean public StringProvider stringProviderTwo() { return () -> "two"; } } }
方案2:直接从容器中获取Bean的注册类型(无需实例化)
如果你的Bean是懒加载的,或者不想提前实例化,可以通过BeanDefinitionRegistry获取所有注册的Bean类型,筛选出StringProvider的子类:
@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = GenericTest.Config.class) public class GenericTest { @Autowired private BeanDefinitionRegistry beanDefinitionRegistry; private List<Class<? extends StringProvider>> stringProviderClasses; @PostConstruct public void init() throws ClassNotFoundException { stringProviderClasses = Arrays.stream(beanDefinitionRegistry.getBeanDefinitionNames()) .map(beanDefinitionRegistry::getBeanDefinition) .map(BeanDefinition::getBeanClassName) .map(Class::forName) // 筛选StringProvider的子类,排除接口本身 .filter(clazz -> StringProvider.class.isAssignableFrom(clazz) && !clazz.isInterface()) .collect(Collectors.toList()); } @Test void test() { stringProviderClasses.forEach(clazz -> System.out.println(clazz.getName())); } // 其余代码和之前一致... }
注意事项
- 如果你的
StringProvider实现是Lambda表达式,其对应的Class是匿名内部类,通常没有自定义静态方法。如果需要调用静态方法,建议改用具体的类实现(而非Lambda)。 - 若使用AOP代理,方案1中需要用
AopProxyUtils.ultimateTargetClass(bean)获取真实的目标类,避免拿到代理类。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

