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


83

클래스 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해야 합니까?

답변:


145

간단한 해결책은 다음 과 같이 제네릭을 형식으로 자동 고려하므로 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);

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

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


11
이것은 놀랍습니다. Type Erasure가 이런 일을 불가능하게 만들었다 고 생각했습니다.
John Strickler 2014 년

6
BeanFactory에서 resolvabletype으로 Bean을 어떻게 얻을 수 있습니까?
ceram1 2014 년

@JohnStrickler 나는 또한 이것이 안전하게 할 수 없다고 생각했습니다. 아직 ResolvableType의 구현을 확인하지 않았지만 이제 제네릭 유형을 안전하게 가져올 수 있다는 의미입니까?
xi.lin

2
실제로 어떤 경우에는 Java에서 런타임에서 제네릭 유형을 얻을 수 있습니다. 한 가지 조건은 일반 클래스의 하위 클래스가 있어야한다는 것입니다. 예 : 부모 클래스 public class Parent<T> {}하위 클래스 public class Child extends Parent<Integer> { }및 현재 : Child c = new Child(); System.out.println(((ParameterizedType)c.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);인쇄됩니다class java.lang.Integer
Michał Przybylak

1
이것이 패키지 스캔 빈 자동 구성과 함께 작동합니까? 나는 그렇게 생각하지 않는다.
Preslav Rachev

12

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

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

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

콘크리트 StringItemIntegerItem수업으로 직접 작업한다는 의미 입니까?
user3374518

2

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


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

봄 5+의 BTW
howard791006

1

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

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

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

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

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

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


0

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


0

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.