web-dev-qa-db-ja.com

Springでジェネリック型<T>のBeanを自動配線する方法は?

Item<T>クラスに自動接続する必要がある@ConfigurationというBeanがあります。

@Configuration
public class AppConfig {

    @Bean
    public Item<String> stringItem() {
        return new StringItem();
    }

    @Bean
    public Item<Integer> integerItem() {
        return new IntegerItem();
    }

}

しかし、@Autowire Item<String>を実行しようとすると、次の例外が発生します。

"No qualifying bean of type [Item] is defined: expected single matching bean but found 2: stringItem, integerItem"

Springでジェネリック型Item<T>を自動配線する方法

65
user3374518

単純な解決策は、次のようにジェネリックを@Qualifierの形式として自動的に考慮するため、 Spring 4. にアップグレードすることです。

@Autowired
private Item<String> strItem; // Injects the stringItem bean

@Autowired
private Item<Integer> intItem; // Injects the integerItem bean

実際、次のように、リストに挿入するときにネストされたジェネリックを自動配線することもできます。

// Inject all Item beans as long as they have an <Integer> generic
// Item<String> beans will not appear in this list
@Autowired
private List<Item<Integer>> intItems;

この仕組みは?

新しい ResolvableType クラスは、実際にジェネリック型を操作するロジックを提供します。それを自分で使用して、タイプ情報を簡単にナビゲートおよび解決できます。 ResolvableTypeのほとんどのメソッドは、それ自体がResolvableTypeを返します。次に例を示します。

// Assuming 'field' refers to 'intItems' above
ResolvableType t1 = ResolvableType.forField(field); // List<Item<Integer>> 
ResolvableType t2 = t1.getGeneric(); // Item<Integer>
ResolvableType t3 = t2.getGeneric(); // Integer
Class<?> c = t3.resolve(); // Integer.class

// or more succinctly
Class<?> c = ResolvableType.forField(field).resolveGeneric(0, 0);

以下のリンクの例とチュートリアルをご覧ください。

これがお役に立てば幸いです。

122
Shishir Kumar

Spring 4にアップグレードしたくない場合は、次のように名前で自動配線する必要があります:

@Autowired
@Qualifier("stringItem")
private Item<String> strItem; // Injects the stringItem bean

@Autowired
@Qualifier("integerItem")
private Item<Integer> intItem; // Injects the integerItem bean
10
Rishav Basu

私にとっては仕事です!!


        List<String> listItem= new ArrayList<>();

        ResolvableType resolvableType = ResolvableType.forClassWithGenerics(List.class, String.class);
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setTargetType(resolvableType);
        beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        beanDefinition.setAutowireCandidate(true);

        DefaultListableBeanFactory bf = (DefaultListableBeanFactory) configurableWebApplicationContext.getBeanFactory();

        bf.registerBeanDefinition("your bean name", beanDefinition);
        bf.registerSingleton("your bean name", listItem);
1
howard791006

Spring自動配線戦略は、構成ファイル(application.xml)で定義されます。

定義しない場合、デフォルトはTypeで、spring injectはJDK反映メカニズムを使用します。

だからリスト?文字列?およびList?Item?の場合、タイプは同じList.classであるため、springは注入方法を混乱させました。

そして、上記の人の応答のように、あなたはどのBeanを注入すべきかをspringに伝えるポイント@Qualifierでなければなりません。

annotationではなく、Beanを定義するためのSpring構成ファイルが好きです。

<bean>
 <property name="stringItem">
        <list>
              <....>
        </list>
 </property>
1
zg_spring

Spring 4.0は、@ Qualifierアノテーションを使用した答えです。お役に立てれば

0
shikjohari

ジェネリックとは何の関係もないと思います...同じタイプの2つの異なるBeanを注入する場合、Springがそれらを識別するのを助ける修飾子を提供する必要があります。

...他の場所

@Configuration
@Bean
public Item stringItem() {
    return new StringItem();
}

@Bean
public Item integerItem() {
    return new IntegerItem();
}

これらのような非ジェネリック宣言がある場合、Springがそれらを識別するのを助けるために修飾子を追加する必要があります...

@Autowired
**@Qualifier("stringItem")**
private Item item1;

@Autowired
**@Qualifier("integerItem")**
private Item item2;

もちろん、バージョン4以降では、リゾルバを介してジェネリック型が考慮されます。これは非常にクールです...

0
Ramkumar S