Tự động nối dây một Danh sách bằng cách sử dụng lược đồ mang lại NoSuchBeanDefinitionException


90

Tôi có một bean mà tôi muốn đưa vào danh sách có tên bằng cách sử dụng không gian tên <util:list id="myList">Spring using nhưng Spring đang tìm kiếm một bộ sưu tập các bean có kiểu String để thay thế. Bài kiểm tra hỏng của tôi là:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ListInjectionTest {

    @Autowired @Qualifier("myList") private List<String> stringList;

    @Test public void testNotNull() {
        TestCase.assertNotNull("stringList not null", stringList);
    }
}

Bối cảnh của tôi là:

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

Nhưng tôi nhận được

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)

Điều khiến tôi khó hiểu hơn là khi tôi nghĩ rằng đây sẽ là cách nó được mong đợi.

Câu trả lời:


171

Điều này là do một phần khá khó hiểu trong hành vi của @ Autowosystem, được chỉ định trong 3.11.2. @ Không mong muốn :

Nó cũng có thể cung cấp tất cả các loại đậu của một loại cụ thể từ ApplicationContext bằng cách thêm chú thích vào một trường hoặc phương thức mong đợi một mảng thuộc loại đó ...

Điều tương tự cũng áp dụng cho các bộ sưu tập đã nhập ...

Nói cách khác, bằng cách nói @Autowired @Qualifier("myList") List<String>, bạn thực sự đang yêu cầu "cho tôi danh sách tất cả các loại đậu java.lang.Stringcó từ" myList ".

Giải pháp được đề cập trong 3.11.3. Tinh chỉnh tính năng tự động cung cấp dựa trên chú thích với các vòng loại :

Nếu bạn có ý định thể hiện việc tiêm theo hướng chú thích bằng tên, không chủ yếu sử dụng @Autowired- ngay cả khi về mặt kỹ thuật có khả năng tham chiếu đến tên bean thông qua @Qualifier các giá trị. Thay vào đó, hãy thích @Resource chú thích JSR-250 được định nghĩa theo ngữ nghĩa để xác định một thành phần đích cụ thể bằng tên duy nhất của nó, với kiểu được khai báo là không liên quan cho quá trình đối sánh.

Như một hệ quả cụ thể của sự khác biệt ngữ nghĩa này, các bean được tự xác định là một kiểu tập hợp hoặc bản đồ không thể được đưa vào @Autowiredvì đối sánh kiểu không được áp dụng đúng cho chúng. Sử dụng @Resourcecho các loại đậu như vậy, đề cập đến bộ sưu tập / đậu bản đồ cụ thể theo tên riêng.

Vì vậy, hãy sử dụng điều này trong thử nghiệm của bạn và nó hoạt động tốt:

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

9
Cuộc sống của bạn an toàn hơn và stackoverflow.com cũng vậy! :)
Rihards

5
Tôi sẽ cho mười phiếu bầu này nếu tôi có thể. Bạn là Da Man, skaffman.
duffymo

3
Thực tế là nhiều người đã bị nhầm lẫn bởi điều này có nghĩa là ngữ nghĩa thực sự khó hiểu. Tôi tự hỏi lý do đằng sau thiết kế khó hiểu như vậy là gì.
supertonsky

3
Chà, tôi coi Spring là một trong những lĩnh vực lập trình mạnh nhất của tôi và tôi chưa bao giờ gặp phải vấn đề này cho đến hôm nay và bạn đã tiết kiệm cho tôi rất nhiều thời gian. Cảm ơn!
Avi

2
Bất kỳ gợi ý nào về cách làm cho điều này hoạt động với phương thức / hàm tạo, chẳng hạn như @Resource không hỗ trợ tham số?
cjbooms

0

Một điều khác có thể xảy ra là bạn đang tự động xác nhận một thuộc tính của bean. Trong trường hợp này, bạn không cần phải tự động phát nó, mà chỉ cần tạo phương thức setter và sử dụng thẻ thuộc tính trong ví dụ về định nghĩa bean (khi sử dụng 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>

Và cả lớp:

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;
}

Xem, không có @Autowiredchú thích trong lớp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.