Autowire Generic Type Spring 4.1.7

时间:2015-09-11 22:44:02

标签: java spring generics autowired

我在Spring版本中工作时大于4。 我使用@Configuration配置了相同超类的bean

@Configuration
public Class ConfigClass{

  @Bean
  public Apple apple(){stuff to return apple bean}

  @Bean
  public Orange orange(){stuff to return orange bean}

}

我有一个可能由这两个豆子中的任何一个组成的豆子

@Component
public Class FruitEater<ReturnType extends Fruit>{

  @Bean
  ReturnType fruit;

}

我得到了这个美丽的歧义错误信息:

没有定义[fruit]类型的限定bean:期望的单个匹配bean但找到2:appleInjection,orangeInjection of autowired dependencies failed;嵌套异常是org.springframework.beans.factory.BeanCreationException:无法自动装配字段:fruiteater.bean;嵌套异常是org.springframework.beans.factory.NoUniqueBeanDefinitionException:没有定义[fruit]类型的限定bean:期望的单个匹配bean但找到2:apple,orange

我的想法是,由于ReturnType应该在编译时解析,因此spring应该能够基于Generic Type进行Autowire。我听说过Spring的ResolvableType,但我不知道如何利用它,因为我还是Spring的新手。 有没有办法解决这个问题并让FruitEater成为通用的FruitEater?

提前谢谢。

1 个答案:

答案 0 :(得分:1)

您已经声明了一个单例(默认)FruitEater bean。单身豆是(YMMV)急切初始化。

在您的情况下,Spring会看到FruitEater类型的bean定义,但就是这样。没有参数化(ReturnType的参数),没有提示应该注入fruit的内容。它无法在两个AppleOrange bean之间进行选择。

据推测,如果您使用原型范围(或类似的东西)声明FruitEater而不是单身,并且有注射目标,例如

@Autowired
private FruitEater<Apple> fruitEater;

要注入的bean将在注入时创建,并且将有足够的类型信息来创建它并注入其字段,即。这个例子中有一个Apple bean。

目前不支持此功能。

一种解决方案是删除FruitEater bean声明(@Component),而是提供适当的参数化子类型

@Component
class OrangeEater extends FruitEater<Orange> {
}

class FruitEater<ReturnType extends Fruit> {
    @Autowired
    protected ReturnType fruit;
}

现在,Spring已经足够聪明,使用extends子句中提供的类型信息来创建OrangeEater bean并在Orange字段中注入fruit。 / p>

完整示例

public class Sample {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigClass.class);
        System.out.println(ctx.getBean(Injected.class).orangerEater);
        System.out.println(ctx.getBean(Injected.class).appleEater);
    }

    @Component
    static class Injected {
        @Autowired
        FruitEater<Orange> orangerEater;

        @Autowired
        FruitEater<Apple> appleEater;
    }
}

@Configuration
@ComponentScan
class ConfigClass {

    @Bean
    public Apple apple() {
        return new Apple();
    }

    @Bean
    public Orange orange() {
        return new Orange();
    }
}

class Fruit {
}

class Apple extends Fruit {
}

class Orange extends Fruit {
}

@Component
class AppleEater extends FruitEater<Apple> {
}

@Component
class OrangeEater extends FruitEater<Orange> {
}

class FruitEater<ReturnType extends Fruit> {
    @Autowired
    protected ReturnType fruit;
}

或者,抛弃组件扫描。使用构造函数注入。

public FruitEater(ReturnType fruit) {
    this.fruit = fruit;
}

然后明确声明bean

@Bean
public FruitEater<Apple> appleEater() {
    return new FruitEater(apple());
}