Выбор компонента Spring при автоваринге
Допустим, есть класс Animal и дочерние от него классы Dog, Cat. Есть также компоненты Spring, обрабатывающие эти классы:
@Component
class AnimalService {
void process(Animal animal) {...}
}
@Component
class DogService extends AnimalService {
@Override
void process(Animal animal) {...}
}
@Component
class CatService extends AnimalService {
@Override
void process(Animal animal) {...}
}
В другом классе есть автоваринг AnimalService:
@Autowired
AnimalService animalService;
Можно ли сделать так, чтобы при вызове метода process, в зависимости от того, к какому подклассу принадлежит переменная animal выбирался соответствующий подкласс сервиса?
Ответы (1 шт):
Автор решения: Alexandr
→ Ссылка
Можно сделать как-то так:
interface AnimalService<A extends Animal> {
void process(A animal);
Class<A> getType();
}
abstract class AbstractAnimalService<A extends Animal>
implements AnimalService<A> {
private final Class<A> clazz;
public AbstractAnimalService(Class<A> clazz) {
this.clazz = clazz;
}
@Override
public Class<A> getType() {
return clazz;
}
}
@Component
public class DogService extends AbstractAnimalService<Dog> {
public DogService() {
super(Dog.class);
}
public void process(Dog dog) {
// Process dog
}
}
@Component
public class CatService extends AbstractAnimalService<Cat> {
public CatService() {
super(Cat.class);
}
public void process(Cat cat) {
// Process cat
}
}
@Component
public class UniversalAnimalService implements AnimalService<Animal> {
private final Map<Class<Animal>, AnimalService<Animal>> animalServices;
@Autowired
public UniversalAnimalService(
List<AbstractAnimalService<Animal>> animalServices) {
this.animalServices =
animalServices.stream()
.collect(
Collectors.toMap(
AnimalService::getType,
as -> as));
}
public void process(Animal animal) {
if (isNull(animal)) {
return;
}
AnimalService<Animal> animalService =
animalServices.get(animal.getClass());
if (isNull(animalService)) {
throw new IllegalArgumentException(
String.format(
"Unknown animal class [%s].",
animal.getClass()));
}
animalService.process(animal);
}
public Class<Animal> getType() {
return Animal.class;
}
}