我有一个接口Animal
,具有两个实现Cat
和Dog
。这两个实现是春季@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;
}
}
答案 0 :(得分:1)
由于两个MyTestController
都是一个bean,所以自动装配/初始化发生在之前,您实际上开始使用类实例本身。我的意思是,当您实际在控制器上触发REST请求时,注入的animal
bean应该已经存在了!
更具体地说,如果您有两个类在没有进一步说明的情况下实现相同的接口(Animal
)(活动Profiles或@Primary
注释),Spring将无法决定在注入时使用哪种实现创建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时基于某个变量进行连接,建议您查看以下资源:
最后,我要指出的是,这样的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);
}