유틸리티 스키마를 사용하여 목록을 자동 연결하면 NoSuchBeanDefinitionException이 발생합니다.


90

Spring util 네임 스페이스를 사용하여 명명 된 목록으로 주입하고 싶은 Bean이 <util:list id="myList">있지만 Spring은 대신 String 유형의 Bean 컬렉션을 찾고 있습니다. 내 깨진 테스트는 다음과 같습니다.

@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)

이것이 작동 할 것으로 예상되는 방식이 될 것이라고 생각했기 때문에 오히려 나를 당혹스럽게 생각합니다.

답변:


171

이것은 3.11.2에 지정된 @Autowired의 동작 중 다소 모호한 부분 때문입니다 . @Autowired :

ApplicationContext해당 유형의 배열을 예상하는 필드 또는 메소드에 주석을 추가하여 특정 유형의 모든 Bean을 제공 할 수도 있습니다 .

입력 된 컬렉션에도 동일하게 적용됩니다 ...

즉, "myList"한정자가있는 @Autowired @Qualifier("myList") List<String>모든 유형의 Bean 목록을 제공합니다 java.lang.String.

해결책은 3.11.3에 언급되어 있습니다. 한정자를 사용하여 주석 기반 자동 연결 미세 조정 :

어노테이션 구동 주입을 이름으로 표현하려는 @Autowired경우 기술적으로 @Qualifier 값을 통해 Bean 이름을 참조 할 수 있더라도 주로 사용하지 마십시오 . 대신 @Resource 선언 된 유형이 일치 프로세스와 관련이없는 고유 한 이름으로 특정 대상 구성 요소를 식별하도록 의미 론적으로 정의 된 JSR-250 주석을 선호합니다 .

이러한 의미의 차이로 인해 자체적으로 컬렉션 또는 맵 유형으로 정의 된 Bean은 @Autowired유형 일치가 적절하게 적용되지 않으므로이를 통해 주입 할 수 없습니다 . @Resource고유 한 이름으로 특정 콜렉션 / 맵 Bean을 참조하여 이러한 Bean에 사용하십시오 .

따라서 테스트에서 이것을 사용하면 잘 작동합니다.

@Resource(name="myList") private List<String> stringList;

9
당신은 더 안전한 삶이며 stackoverflow.com도 마찬가지입니다! :)
Rihards

5
내가 할 수만 있다면이 10 표를 주겠다. 당신은 Da Man, skaffman입니다.
duffymo 2011-06-24

3
많은 사람들이 이로 인해 혼란스러워 졌다는 사실은 의미론이 정말 혼란 스럽다는 것을 의미합니다. 그런 혼란스러운 디자인의 이유가 무엇인지 궁금합니다.
supertonsky

3
와우, 저는 Spring을 프로그래밍에서 가장 강력한 분야 중 하나로 생각하고 오늘까지이 문제를 접한 적이 없으며 당신은 저에게 많은 시간을 절약했습니다. 감사!
Avi

2
@Resource가 매개 변수를 지원하지 않기 때문에 생성자 / 메소드 주입과 함께 작동하도록하는 방법에 대한 제안이 있습니까?
cjbooms

0

일어날 수있는 또 다른 일은 빈의 속성을 자동 연결하는 것입니다. 이 경우 자동 배선 할 필요는 없지만 setter 메서드를 만들고 빈 정의 (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클래스에 주석이 없습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.