Автоматическое подключение любого интерфейса с использованием Spring Boot - PullRequest
0 голосов
/ 14 апреля 2020

Я хочу autowire класс, который реализуется в компоненте. Вот часть интерфейса:

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GenericResourceHandlerService<T extends ResourceRequest, A extends ResultType, B extends ResourceService<T, A>> {

    private final B service;

    public Response get(String x) {
        various checks(x, service.getType());

        B res = service.get(x);

        if (res!= null) {
            return Response.status(Response.Status.OK).entity(res).build();
        } else {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
    }
}

Тогда класс, реализующий ResourceService, будет выглядеть так:

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TypeOneService implements EntityService<CityRequest, City> {

    private final Repository repository;

    @Override
    public ResultType getType() {
        return ResultType.TYPE_ONE;
    }

    @Timed
    public TYPE_ONE get(String resource) {
        return repository.get(resource);
    }

}

А сам интерфейс выглядит так:

public interface EntityService<T extends EntityRequest, A extends ReturnableEntity> {

    ResourceType getResourceType();

    A get(String resource);

}

Теперь у меня есть набор контроллеров, которые пытаются автоматически связать GenericResourceHandlerService и вызвать метод get. Это выглядит так:

public class TypeOneController {

    private final TypeOneService typeOneService;

    private final GenericResourceHandlerService<TypeOneRequest, TypeOne, TypeOneService> genericResourceHandlerService;

    public Response getListItemByResource(
        String resource
    ) {
        return genericResourceHandlerService.get(resource);
    }
}

Или вот это:

public class TypTwoController {

    private final TypeTwoService typeTwoService;

    private final GenericResourceHandlerService<TypeTwoRequest, TypeTwo, TypeTwoService> genericResourceHandlerService;

    public Response getListItemByResource(
        String resource
    ) {
        return genericResourceHandlerService.get(resource);
    }
}

Компилируется, но когда приложение запускается, я получаю следующее сообщение об ошибке:

Parameter 0 of constructor in path.GenericResourceHandlerService required a single bean, but 2 were found:
    - typeOneSerivce: defined in file [C:\Path\TypeOneService.class]
    - typeTwoService: defined in file [C:\Path\TypeTwoService.class]

Я думаю, это потому, что Spring Boot не может определить, какой из них обслуживать для автоматического подключения. Возможно ли то, что я пытаюсь сделать?

1 Ответ

0 голосов
/ 14 апреля 2020

Spring пытается внедрить bean-компонент для разрешения GenericResourceHandlerService.service, но служба имеет тип B, а B расширяет ResourceService. И Spring нашел 2 bean-компонента, реализующих этот интерфейс, поэтому не знает, какую реализацию использовать для автоматического подключения ..

Вы можете поместить @Qualifier в поле service, но я думаю, вы потеряете универсальность этого типа GenericResourceHandlerService

Возможно, лучший способ - это позволить контроллеру пройти через реализацию в GenericResourceHandlerService и позволить этому продлиться как простой pojo .. а не как bean-компонент (так что удалите @Service on GenericResourceHandlerService

Вот так

public class TypeOneController {

@Autowired
private final TypeOneService typeOneService;

private final GenericResourceHandlerService<TypeOneRequest, TypeOne, TypeOneService> genericResourceHandlerService = new GenericResourceHandlerService(typeOneService);

public Response getListItemByResource(
    String resource
) {
    return genericResourceHandlerService.get(resource);
}

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...