[java] Spring에서 일반 유형 <T>의 Bean을 Autowire하는 방법은 무엇입니까?

클래스 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"

Item<T>Spring에서 제네릭 유형 을 어떻게 Autowire해야 합니까?



답변

간단한 해결책은 다음 과 같이 제네릭을 형식으로 자동 고려하므로 Spring 4.0 으로 업그레이드 하는 것입니다 @Qualifier.

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

아래 링크에서 예제 및 자습서를 확인하십시오.

도움이 되었기를 바랍니다.


답변

Spring 4로 업그레이드하고 싶지 않다면 아래와 같이 이름으로 자동 연결해야합니다.

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

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


답변

다음은이 질문에 답하기 위해 만든 솔루션입니다.


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


답변

Spring autowired 전략은 구성 파일 (application.xml)에 정의되어 있습니다.

정의하지 않은 경우 기본값은 유형, 스프링 주입은 JDK 반사 메커니즘을 사용합니다.

그래서 목록? 문자열? 및 List? Item ?, 유형은 동일한 List.class이므로 주입 방법을 혼동합니다.

그리고 위의 사람 응답과 같이, 당신은 어떤 빈이 주입되어야 하는지를 스프링에게 알려주기 위해 포인트 @Qualifier이어야합니다.

나는 Annotation보다는 bean을 정의하는 spring configration 파일을 좋아합니다.

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


답변

Spring 4.0은 @Qualifier 주석 사용에 대한 답입니다. 도움이 되었기를 바랍니다


답변

제네릭과는 아무런 관련이 없다고 생각합니다. 같은 유형의 두 가지 다른 빈을 주입하는 경우 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를 고려합니다.


답변