การเดินสายรายการโดยอัตโนมัติโดยใช้ util schema ให้ NoSuchBeanDefinitionException


90

ฉันมี bean ที่ฉันต้องการฉีดด้วยชื่อรายการโดยใช้ Spring util namespace <util:list id="myList">แต่ Spring กำลังมองหาชุดของ bean ประเภท 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)

ซึ่งเป็นปริศนาที่ทำให้ฉันคิดว่านี่น่าจะเป็นวิธีที่คาดว่าจะได้ผล

คำตอบ:


171

สาเหตุนี้เกิดจากพฤติกรรมของ @ Autowired ที่ค่อนข้างคลุมเครือซึ่งระบุไว้ใน3.11.2 @ อัตโนมัติ :

นอกจากนี้ยังเป็นไปได้ที่จะจัดเตรียมถั่วชนิดใดประเภทหนึ่ง ApplicationContextโดยการเพิ่มคำอธิบายประกอบลงในฟิลด์หรือวิธีการที่คาดว่าจะมีอาร์เรย์ของประเภทนั้น ...

เช่นเดียวกับคอลเล็กชันที่พิมพ์ ...

กล่าวอีกนัยหนึ่งคือ@Autowired @Qualifier("myList") List<String>คุณกำลังขอ "ขอรายชื่อถั่วทั้งหมดjava.lang.Stringที่มีคุณสมบัติ" myList "ให้ฉัน

วิธีแก้ปัญหาถูกกล่าวถึงใน3.11.3 การปรับแต่งคำอธิบายประกอบอัตโนมัติโดยใช้คุณสมบัติ :

หากคุณต้องการแสดงการแทรกคำอธิบายประกอบตามชื่ออย่าใช้เป็นหลัก@Autowiredแม้ว่าจะสามารถอ้างถึงชื่อ bean ผ่าน@Qualifier ค่าในทางเทคนิคได้ แต่ชอบ@Resource คำอธิบายประกอบJSR-250 ซึ่งกำหนดตามความหมายเพื่อระบุส่วนประกอบเป้าหมายที่เฉพาะเจาะจงด้วยชื่อเฉพาะโดยประเภทที่ประกาศไม่เกี่ยวข้องกับกระบวนการจับคู่

ผลที่ตามมาเฉพาะของความแตกต่างทางความหมายนี้ถั่วที่กำหนดเองเป็นคอลเลคชันหรือประเภทแผนที่ไม่สามารถแทรกผ่านได้ @Autowiredเนื่องจากการจับคู่ประเภทไม่สามารถใช้ได้อย่างถูกต้อง ใช้ @Resourceสำหรับถั่วดังกล่าวอ้างอิงถึงคอลเลคชันเฉพาะ / map bean ตามชื่อเฉพาะ

ดังนั้นใช้สิ่งนี้ในการทดสอบของคุณและมันก็ใช้ได้ดี:

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

9
คุณมีชีวิตที่ปลอดภัยขึ้นและก็คือ stackoverflow.com! :)
Rihards

5
ฉันจะให้สิบโหวตถ้าทำได้ คุณคือดามันสกัฟแมน
duffymo

3
ความจริงที่ว่าหลายคนสับสนโดยวิธีนี้หมายถึงความหมายที่สับสนจริงๆ ฉันสงสัยว่าอะไรคือเหตุผลเบื้องหลังการออกแบบที่สับสนเช่นนี้
supertonsky

3
ว้าวฉันถือว่า Spring เป็นหนึ่งในพื้นที่ที่แข็งแกร่งที่สุดของฉันในการเขียนโปรแกรมและฉันไม่เคยพบปัญหานี้เลยจนถึงวันนี้และคุณช่วยฉันได้มากมาย ขอบคุณ!
Avi

2
ข้อเสนอแนะใด ๆ เกี่ยวกับวิธีทำให้สิ่งนี้ทำงานกับ constructor / method injection เนื่องจาก @Resource ไม่รองรับพารามิเตอร์?
cjbooms

0

อีกสิ่งหนึ่งที่อาจเกิดขึ้นคือคุณกำลังสร้างคุณสมบัติของถั่วโดยอัตโนมัติ ในกรณีเช่นนี้คุณไม่จำเป็นต้องกำหนดเส้นทางอัตโนมัติ แต่เพียงแค่สร้างเมธอด 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คำอธิบายประกอบในชั้นเรียน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.