如何在 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 更喜欢按以下顺序自动装配对象:
- 默认值使用
@Value
- 使用类型参数的多个 bean。
- 匹配字段类型的单个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 作为列表中的元素。
我的配置 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 更喜欢按以下顺序自动装配对象:
- 默认值使用
@Value
- 使用类型参数的多个 bean。
- 匹配字段类型的单个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 作为列表中的元素。