Как 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?
Ответы
Ответ 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 через резольверы, что очень круто...