如何在 spring 框架中@Autowired 列表<Integer>

How to @Autowired a List<Integer> in spring framework

我的配置 class 如下:

@Configuration
public class ListConfiguration {
    @Bean
    public List<Integer> list() {
        List<Integer> ints = new ArrayList<>();
        ints.add(1);
        ints.add(2);
        ints.add(3);
        return ints;
    }

    @Bean
    public int number() {
        return 4;
    }
}

我也有一个测试class如下

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = ListConfiguration.class)
public class ListTest {
    @Autowired
    List<Integer> ints;

    @Test
    public void print() {
        System.out.println(ints.size());
        System.out.println(ints);
    }
}

但是print方法的输出是1[4],为什么不是3[1,2,3]呢?非常感谢您的帮助!

可能是 Spring 将所有 Integer 类型的 bean 注入到 List 而不是您声明的自动装配 List<Integer> bean。

如果您在测试中的注入点添加 @Qualifier("list"),那么它可能会提供您期望的行为。

您的应用程序上下文中有一个 Integer 类型的 bean 和一个 List<Integer> 类型的 bean。

很明显,您要自动装配的 bean 属于 List<Integer> 类型,它确实符合自动装配的候选条件。为了发现 Spring 实际上是如何自动装配字段的,我不得不深入研究 AutowiredAnnotationBeanPostProcessor class.

TL;我调查的 DR 是 Spring 更喜欢按以下顺序自动装配对象:

  1. 默认值使用@Value
  2. 使用类型参数的多个 bean。
  3. 匹配字段类型的单个bean。

这意味着如果你正在自动装配 List<Integer> Spring 将尝试将多个 Integer beans 自动装配到列表中,然后它会尝试自动装配单个 List<Integer>豆.

您可以在 DefaultListableBeanFactory class 中看到此行为。

下面的相关片段:

public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
        Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

    Class<?> type = descriptor.getDependencyType();
    //Searches for an @Value annotation and 
    Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
    if (value != null) {
        //Handle finding, building and returning default value
    }
    /* 
     * Check for multiple beans of given type. Because a bean is returned here,
     * Spring autowires the Integer bean instance.
     */
    Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
    if (multipleBeans != null) {
        return multipleBeans;
    }
    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        // Do more stuff here to try and narrow down to a single instance to autowire.
    }
}

希望这能解释为什么当您在应用程序上下文中有该类型的单个 bean 时,在尝试自动装配该类型的列表时确实需要使用 @Qualifer 注释。

编辑: 值得注意的是,这不是好的做法。创建基元集合或基元包装器并将其注册为 bean 会导致问题。最好的方法是使用 @Value 并在属性文件中定义原语列表,Spring 会选择。

示例:

application.properties 文件

list=1,2,3,4

在您的配置中 class 声明以下 bean:

@Bean 
public ConversionService conversionService() {
    return new DefaultConversionService();
}

默认转换服务用于将属性文件中声明的逗号分隔值转换为类型安全的对象集合。

Class 使用它:

@Value("${list}")
private List<Integer> anotherList;

anotherList 将包含 1,2,3 & 4 作为列表中的元素。