Подтвердить что ты не робот

Как Autowire Bean общего типа <T> в Spring?

У меня есть bean Item<T>, который требуется для автоподготовки в классе @Configuration.

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

Как я должен Autowire общий тип Item<T> в Spring?

4b9b3361

Ответ 1

Простым решением является переход на Spring 4.0, поскольку он автоматически рассмотрит дженерики как форму @Qualifier, как показано ниже:

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

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

Infact, вы можете даже автонастраивать вложенные генерики при введении в список, как показано ниже:

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

Ознакомьтесь с примерами и учебными пособиями по ссылкам ниже.

Надеюсь, это поможет вам.

Ответ 2

Если вы не хотите обновляться до Spring 4, вам необходимо автоушилить по имени, как показано ниже:

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

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

Ответ 3

Spring autowired strategy определяется в файле конфигурации (application.xml).

если вы не определили, по умолчанию используется тип, spring использовать механизм JDK для отражения.

поэтому List? String? и List? Item?, тип такой же List.class, поэтому spring запутался, как вставлять.

и, как указано выше, вам следует указать point @Qualifier, чтобы сообщить spring, который следует ввести bean.

Мне нравится spring файл конфигурации, чтобы определить bean, а не Annotation.

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

Ответ 4

Spring 4.0 - это ответ с использованием аннотации @Qualifier. Надеюсь, что это поможет

Ответ 5

Это работа для меня!


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

Ответ 6

Я считаю, что это не имеет ничего общего с дженериками... Если вы вводите два разных beans одного типа, тогда вам нужно предоставить квалификатор, чтобы помочь 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 и выше Spring рассматривает Generic Types через резольверы, что очень круто...