是否可以通过@Autowire根据路径变量来决定使用哪种bean?

时间:2019-05-17 09:22:08

标签: java spring spring-boot

这些天我在玩Spring,在HTTP请求生命周期内尝试自动装配bean时,我陷入了困境。

我有一个名为Animal的接口和两个实现,DogCat如下:

Animal.java

public interface Animal {
  public String sound();
}

Dog.java

public class Dog implements Animal {
  @Override
  public String sound() {return "Woof!";}
}

Cat.java

public class Cat implements Animal {
  @Override
  public String sound() {return "Meow... :3";}
}

我的控制器如下:

AnimalController.jav a

@RestController
@RequestMapping(value="/animal")
public class AnimalController {
  private final AnimalService animalService;

  @Autowired
  public AnimalController(AnimalService service) {
    animalService = service;
  }

  @GetMapping(value = "/{animal}/sound")
  public String animalSound(@PathVariable String animal) {
    return animalService.doSound();
  }
}

AnimalService.java (在这里,我无法为动物自动装配线):

@Service
public class AnimalService {

/* 
 My IDE prompts:  
 'Could not autowire. There is more than one bean of `Animal` type.'
*/
  @Autowired
  private Animal animal; 

  public String doSound() {
    return animal.sound();
  }
}    
}

也:

Configuration.java

@Configuration
public class Configuration {
  @Bean
  public Dog createDog() {
    return new Dog();
  }

  @Bean
  public Cat createCat() {
    return new Cat();
  }
}

是否有这种行为可以根据路径变量来决定使用哪种bean?我尝试阅读Spring的核心文档,但是我不太了解。我将不胜感激。

3 个答案:

答案 0 :(得分:2)

您可以通过将所有Animal类型的bean列为一个实例来实例化它们。 例如:

@Autowired
List<Animal> animals;

这将为所有动物自动装配电线,您可以遍历它们并以编程方式决定您需要的动物。

尽管我可能是错的,但是对于您的用例,我相信Factory设计模式会更合适。您可以制作一个抽象的AnimalFactory并自动连接列表中的所有工厂,然后应用某种策略模式以编程方式决定要使用的工厂并返回该类型的新对象。

答案 1 :(得分:1)

您可以使用spring.profiles.active来实现。一个配置文件将狗加载,另一配置文件将猫加载。

  @Configuration
public class Configuration {

@Profile("dog")
  @Bean
  public Dog createDog() {
    return new Dog();
  }

@Profile("cat")
  @Bean
  public Cat createCat() {
    return new Cat();
  }
}

您可以像java -jar myapp.jar --spring.profiles.active = dog一样启动您的应用。

您可以尝试的另一种选择是限定Bean并使用带有属性变量的Qualifier,spring可以解决它。

@Service
public class AnimalService {

  @Qualifier("${choosen.animal}")
  @Autowired
  private Animal animal; 

  public String doSound() {
    return animal.sound();
  }
}    
}

答案 2 :(得分:1)

通过beanName从Container中获取动物bean;

@RestController
@RequestMapping(value="/animal")
public class AnimalController {

private final AnimalService animalService;

  @Autowired
  public AnimalController(AnimalService service) {
    animalService = service;
  }


  @GetMapping(value = "/{animal}/sound")
  public String animalSound(@PathVariable String animal) {
    return animalService.doSound(animal);
  }

} 

AnimalService.java

public class AnimalService implements ApplicationContextAware {

private ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
}


public String doSound(String animalName) {
    Animal animal = applicationContext.getBean(animalName);
return animal.sound();
 }

}