有条件地基于值自动装配bean实现吗?

时间:2018-08-16 06:25:56

标签: spring spring-boot

我有一个接口Animal,具有两个实现CatDog。这两个实现是春季@Component。如何根据值有条件地连接这两个?我知道我可能必须将MyTestController的范围从单例更改为请求。

@RestController
public class MyTestController {

    @Autowired
    Animal animal;// how to wire bean of Cat or Dog based on animalName

    @PostMapping("/get-animal")
    public @ResponseBody Animal getAnimal(@RequestParam(value = "animalName") String animalName) {
        return animal;

    }

}

2 个答案:

答案 0 :(得分:1)

由于两个MyTestController都是一个bean,所以自动装配/初始化发生在之前,您实际上开始使用类实例本身。我的意思是,当您实际在控制器上触发REST请求时,注入的animal bean应该已经存在了!

更具体地说,如果您有两个类在没有进一步说明的情况下实现相同的接口(Animal)(活动Profiles或@Primary注释),S​​pring将无法决定在注入时使用哪种实现创建MyTestController

您要做的是根据参数/类名从ApplicationContext返回bean。看起来像这样:

@Autowired
private ApplicationContext context;

/* ... */
if(animalName.equals("dog") {
  context.getBean(Dog.class) //returning the dog bean
} else if(animalName.equals("cat") {
  context.getBean(Cat.class) //returning the cat bean
}

编辑 IMO这个问题有点令人困惑。您要求根据一个值连接bean,但是该值仅在运行时出现。因此,我的答案。但是,如果要在初始化bean时基于某个变量进行连接,建议您查看以下资源:

  • Profiles-使用配置文件,您可以告诉spring要在哪种配置中注入哪个实例。 (例如:生产/开发/测试配置,以及每个要注入不同bean的配置)
  • Primary-您的一个bean在注入它时优先于另一个。
  • Qualifier

最后,我要指出的是,这样的IoC倒置被认为是一种不好的做法。 (请参见here

答案 1 :(得分:0)

好吧,您遗漏了所有要点。不要自动连线简单的DTO,而是自动连线AnimalFactory或某种AnimalRepository(或更好的Service),您可以在其中根据动物类型创建或检索动物。

它看起来像这样:

@Component
public class AnimalFactory {

  public Animal createAnimal(String animalType) {
     switch (animalType) {
       case "DOG":
        return new Dog();
       case "CAT":
        return new Cat();
     }
     throw new IllegalArgumentException("AnimalType is invalid");
  }

}

动物Spring数据JPA存储库:

@Component
public class AnimalRepository implements JpaRepository<Animal, Long> {

  public Optional<Animal> findByAnimalName(String animalName);

}