utilスキーマを使用してリストを自動配線すると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を提供することもでき ます...

同じことが型付きコレクションにも当てはまります...

つまり、と言うことで@Autowired @Qualifier("myList") List<String>、実際には「java.lang.String修飾子「myList」を持つタイプのすべてのBeanのリストを教えてください」と要求しています。

解決策は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、2011年

5
できれば、この10票を投票します。あなたはダマン、スカフマンです。
duffymo

3
これによって多くが混乱しているという事実は、セマンティクスが本当に混乱していることを意味します。そんなわかりにくいデザインの理由は何だったのでしょうか。
supertonsky 2012年

3
うわー、私は春をプログラミングの私の最も強力な分野の1つと見なしており、今日までこの問題に遭遇したことがなく、あなたは私に多くの時間を節約しました。ありがとう!
Avi 2016

2
@Resourceがパラメーターをサポートしていないため、これをコンストラクター/メソッドインジェクションと連携させる方法についての提案はありますか?
cjbooms 16

0

発生する可能性のあるもう1つのことは、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クラスにアノテーションがありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.