Автоматическая проводка списка с использованием схемы util дает NoSuchBeanDefinitionException
У меня есть bean, который я хочу добавить с именованным списком, используя Spring util namespace <util:list id="myList">
, но Spring ищет коллекцию beans типа String. Мой сломанный тест:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ListInjectionTest {
@Autowired @Qualifier("myList") private List<String> stringList;
@Test public void testNotNull() {
TestCase.assertNotNull("stringList not null", stringList);
}
}
Мой контекст:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<util:list id="myList">
<value>foo</value>
<value>bar</value>
</util:list>
</beans>
Но я получаю
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [java.lang.String] found for dependency [collection of java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=myList)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:726)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:571)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:412)
Что меня озадачивает, так как я полагал, что это будет так, как ожидается, что он будет работать.
Ответы
Ответ 1
Это связано с довольно неясной частью @Autowired поведения, указанной в 3.11.2. @Autowired:
Можно также предоставить все beans определенного типа из ApplicationContext
, добавив аннотация к полю или методу, который ожидает массив такого типа...
То же самое относится к типизированным коллекциям...
Другими словами, говоря @Autowired @Qualifier("myList") List<String>
, вы действительно просите "дать мне список всех beans типа java.lang.String
, у которых есть определитель" myList ".
Решение упоминается в 3.11.3. Тонкая настройка автозапуска на основе аннотаций с квалификаторами:
Если вы намерены выразить аннотация, вводимая по имени, в основном не используйте @Autowired
- даже если технически можно ссылаться к имени bean через @Qualifier
значения. Вместо этого предпочитайте JSR-250 @Resource
аннотация, которая семантически определены для идентификации конкретным целевым компонентом уникальное имя, с объявленным типом не имеет значения для соответствия процесс.
В качестве конкретного следствия этого семантическая разница, beans, которые сами определяются как сбор или тип карты не может быть введен через @Autowired
поскольку сопоставление типов не надлежащим образом применимым к ним. Использование @Resource
для такого beans, ссылаясь на конкретная коллекция/карта bean by уникальное имя.
Поэтому используйте это в своем тесте, и он отлично работает:
@Resource(name="myList") private List<String> stringList;
Ответ 2
Если я использую JBoss 6.1, я обнаружил, что аннотация @Resource привела к ошибке моего развертывания (деталь опущен как не относящийся к вопросу).
Общей альтернативой для всех серверов приложений является использование аннотации @Inject (JSR-330).
Ответ 3
Другая вещь, которая может произойти, заключается в том, что вы autowiring свойство bean. В таком случае вам не нужно его автоустанавливать, но просто создайте метод setter и используйте тег свойства в определении bean (при использовании xml):
<bean id="cleaningUpOldFilesTasklet" class="com.example.mypackage.batch.tasklets.CleanUpOldFilesTasklet">
<property name="directoriesToClean">
<list>
<value>asfs</value>
<value>fvdvd</value>
<value>sdfsfcc</value>
<value>eeerer</value>
<value>rerrer</value>
</list>
</property>
</bean>
И класс:
public class CleanUpOldFilesTasklet extends TransferingFilesTasklet implements Tasklet{
private long pastMillisForExpiration;
private final String dateFormat = "MM.dd";
Date currentDate = null;
List<String> directoriesToClean;
public void setDirectoriesToClean(List<String> directories){
List<String> dirs = new ArrayList<>();
for(String directory : directories){
dirs.add(getSanitizedDir(directory));
}
this.directoriesToClean = dirs;
}
Смотрите, нет @Autowired
аннотации в классе.