it-swarm.com.de

Wie kann man Bean des generischen Typs <T> im Frühling autowire machen?

Ich habe eine Bean Item<T>, die in einer @Configuration-Klasse automatisch benötigt wird.

@Configuration
public class AppConfig {

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

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

}

Wenn ich jedoch @Autowire Item<String> versuche, erhalte ich folgende Ausnahme.

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

Wie soll ich den generischen Typ Item<T> in Spring automatisch abwickeln?

55
user3374518

Eine einfache Lösung ist ein Upgrade auf Spring 4.0 , da Generics automatisch als eine Form von @Qualifier betrachtet werden, wie unten:

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

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

Infact, Sie können sogar verschachtelte Generika autowire, wenn Sie in eine Liste injizieren, wie folgt:

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

Wie funktioniert das?

Die neue ResolvableType -Klasse bietet die Logik für das Arbeiten mit generischen Typen. Sie können es selbst verwenden, um die Typinformationen leicht zu navigieren und aufzulösen. Die meisten Methoden in ResolvableType geben selbst eine ResolvableType zurück, zum Beispiel:

// 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);

Schauen Sie sich die Beispiele & Tutorials unter den Links an.

Hoffe das hilft dir.

114
Shishir Kumar

Wenn Sie kein Upgrade auf Spring 4 durchführen möchten, müssen Sie den Namen wie folgt automatisch wählen:

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

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

Es ist Arbeit für mich !!


        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

Die automatische Strategie für den Frühling ist in Ihrer Konfigurationsdatei (application.xml) definiert.

wenn Sie nicht definiert sind, wird standardmäßig nach Typ verwendet. Der Federeinspritzmechanismus verwendet den JDK-Reflektionsmechanismus.

so Liste? String? und List? Item ?, der Typ ist derselbe List.class, so dass der Frühling verwirrt ist, wie er injiziert.

und wie oben beschrieben, sollten Sie @Qualifier angeben, um herauszufinden, welche Bohne injiziert werden soll.

ich mag es, wenn die Spring-Konfigurationsdatei Bean und nicht Annotation definiert.

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

1
zg_spring

Spring 4.0 ist die Antwort mit der Verwendung der Annotation @Qualifier. Hoffe das hilft

0
shikjohari

Ich glaube, es hat nichts mit Generika zu tun ... Wenn Sie zwei verschiedene Bohnen desselben Typs injizieren, müssen Sie ein Qualifikationsmerkmal angeben, mit dessen Hilfe Spring sie identifizieren kann.

... Anderswo

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

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

Wenn Sie nicht generische Deklarationen wie diese haben, müssen Sie ein Qualifikationsmerkmal hinzufügen, damit Spring sie identifizieren kann ...

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

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

Natürlich berücksichtigt spring ab Version 4 die generischen Typen durch die Resolver, was sehr cool ist ...

0
Ramkumar S