У меня есть интерфейс 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;
}
}
Не проводное подключение. Просто найдите тот, который вам нужен, в своем методе
Возможный дубликат Можно ли условно объявить Spring bean?
@MehrajMalik Не на основе профиля.
Я согласен с М. Дейнумом, за исключением того, что я бы предпочел: автосоединяйте их оба или автосоединяйте List <Animal> и ищите тот, который вам нужен, внутри метода.
Поскольку оба MyTestController являются bean-компонентами, происходит автоматическое подключение / инициализация перед, вы фактически начинаете использовать сам экземпляр класса. Я имею в виду, что к тому времени, когда вы действительно запускаете запросы REST на своем контроллере, внедренный bean-компонент animal уже должен быть там!
В частности, если у вас есть два класса, реализующие один и тот же интерфейс (Animal) без дополнительной спецификации (активные профили или аннотация @Primary), Spring не сможет решить, какую реализацию внедрить при создании MyTestController,
Что вы хотите сделать, так это вернуть bean-компоненты из вашего ApplicationContext на основе имени параметра / класса. Это выглядело бы примерно так:
@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 считается плохой практикой. (См. здесь)
Что ж, вы упускаете из виду весь смысл. Не подключайте простой 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");
}
}
Репозиторий данных Animal Spring JPA:
@Component
public class AnimalRepository implements JpaRepository<Animal, Long> {
public Optional<Animal> findByAnimalName(String animalName);
}
Основан ли этот профиль реализации или вы явно укажете, какой из них использовать?