Spring не может найти реализацию интерфейса Autowired

У меня есть основной класс SpringBootApplication здесь:

package com.example.springproj;

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

Класс @RestController здесь:

package com.example.springproj.controller;

@RestController
@Api("Sample")
public class RefDataController {

    @Autowired
    @Qualifier("RefDataServiceImpl")
    private RefDataService refDataService;

    @GetMapping(path = {"/refdata"}, produces = {"application/json"})
    public ResponseEntity<Configuration> getRefData() {
        // etc
    }
}

Контроллер автоматически подключает этот интерфейс:

package com.example.springproj.service;

public interface RefDataService {

    Configuration getConfiguration(String param);
}

Что реализовано этим классом:

package com.example.springproj.services;
@Service
public class RefDataServiceImpl implements RefDataService {

    @Autowired
    private ConfigRepository config;

    @Value("${ENV}")
    private String environment;

    @Override
    public Configuration getConfiguration(String param) {
        // etc
    }
}

Но когда я запускаю файл App.java, я получаю это

***************************
APPLICATION FAILED TO START
***************************

Description:

Field refDataService in com.citi.icrm.risk.springproj.controller.RefDataController required a bean of type 'com.citi.icrm.risk.springproj.service.RefDataService' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)
    - @org.springframework.beans.factory.annotation.Qualifier(value=RefDataServiceImpl)


Action:

Consider defining a bean of type 'com.citi.icrm.risk.springproj.service.RefDataService' in your configuration.

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

РЕДАКТИРОВАТЬ: Вещи, которые я уже пробовал, включают:

Удаление всех аннотаций @Qualifier

@RestController
@Api("Sample")
public class RefDataController {

    @Autowired
    private RefDataServiceImpl refDataService;

    @GetMapping(path = {"/refdata"}, produces = {"application/json"})
    public ResponseEntity<Configuration> getRefData() {
        System.err.println("testing.");
        return new ResponseEntity<Configuration>(refDataService.getConfiguration("EEMS_USER_DETAIL_URL"), HttpStatus.OK);
    }
}
public class RefDataServiceImpl implements RefDataService {

    @Autowired
    private ConfigRepository config;

    @Value("${ENV}")
    private String environment;

    @Override
    public Configuration getConfiguration(String param) {
        try {
            return config.getConfiguration(param, environment);
        } catch (Exception e) {
            e.printStackTrace();
            throw (RuntimeException) new RuntimeException().initCause(e);
        }
    }
}

Изменение имен bean-компонентов в соответствии с соглашением

@RestController
@Api("Sample")
public class RefDataController {

    @Autowired
    @Qualifier("refDataServiceImpl")
    private RefDataService refDataService;

    @GetMapping(path = {"/refdata"}, produces = {"application/json"})
    public ResponseEntity<Configuration> getRefData() {
        System.err.println("testing.");
        return new ResponseEntity<Configuration>(refDataService.getConfiguration("EEMS_USER_DETAIL_URL"), HttpStatus.OK);
    }
}
@Service("refDataServiceImpl")
public class RefDataServiceImpl implements RefDataService {

    @Autowired
    private ConfigRepository config;

    @Value("${ENV}")
    private String environment;

    @Override
    public Configuration getConfiguration(String param) {
        try {
            return config.getConfiguration(param, environment);
        } catch (Exception e) {
            e.printStackTrace();
            throw (RuntimeException) new RuntimeException().initCause(e);
        }
    }
}

Для справки, файлы попадают в структуру пакета приложения следующим образом:

com.example.springproj
-> com.example.springproj.controller
--> RefDataController
-> com.example.springproj.services
--> RefDataService
-> com.exampple.springproj.services.impl
---> RefDataServiceImpl

Вот структура папок, так как некоторые люди спрашивали:

введите здесь описание изображения


person Kristoff Campbell    schedule 10.12.2019    source источник
comment
Я думаю, проблема в том, что имя RefDataServiceImpl в квалификаторе меняется на refDataServiceImpl   -  person Deadpool    schedule 10.12.2019
comment
можете поделиться структурой папок? Где ваш класс приложений?   -  person Lemmy    schedule 11.12.2019
comment
добавлена ​​структура папок к сообщению.   -  person Kristoff Campbell    schedule 11.12.2019


Ответы (4)


Во-первых, вам не нужен @Qualifier("RefDataServiceImpl"), если у вас есть только одна реализация интерфейса RefDataService. Вам просто нужно

@Autowired
private RefDataService refDataService;

Во-вторых, имя бина генерируется на основе имени класса, но начинается со строчной буквы. В вашем примере имя компонента будет выглядеть как refDataServiceImpl. Итак, вы можете автоматически подключить этот компонент, как показано ниже.

@Autowired
@Qualifier("refDataServiceImpl")
private RefDataService refDataService;

В-третьих, вы можете указать имя бина

@Service("youBeanName")
public class RefDataServiceImpl implements RefDataService

а затем автоматически подключил этот компонент по имени в вашем контроллере, например

@RestController
@Api("Sample")
public class RefDataController {

    @Autowired
    @Qualifier("youBeanName")
    private RefDataService refDataService;

    //....
}
person Mykola Shorobura    schedule 10.12.2019
comment
смотри комментарий к посту выше - person Kristoff Campbell; 10.12.2019

Измените аннотацию @Service в классе RefDataServiceImpl следующим образом:

@Service("RefDataServiceImpl")
public class RefDataServiceImpl implements RefDataService

Имя @Qualifier в сервисе autowired не соответствует bean-компоненту в вашей конфигурации spring. Соглашение об именах по умолчанию — это полный путь к классу. Из-за этого имя, которое Spring, вероятно, использует в вашей конфигурации для службы RefDataServiceImpl, будет следующим: «com.example.springproj.services.RefDataServiceImpl».

Добавлено: эта страница может быть полезной для чтения: https://www.baeldung.com/spring-qualifier-annotation.

Попытка вторая: попробуйте это

@Service
@Qualifier("RefDataServiceImpl")
@Service("RefDataServiceImpl")
public class RefDataServiceImpl implements RefDataService
person DwB    schedule 10.12.2019
comment
Пробовал это: похоже, не работает. Я получаю ту же ошибку. - person Kristoff Campbell; 10.12.2019

Я исправил проблему, поместив RefDataServiceImpl в тот же пакет, что и RefDataService. До этого я хранил его в подпапке основного пакета services. Я все еще уверен, что смогу заставить эту работу работать с подпапкой реализации, но пока это работает как решение.

person Kristoff Campbell    schedule 11.12.2019

Я столкнулся с этой же проблемой, пытаясь реализовать класс с запросом к базе данных. Добавление @Repository в начало реализованного класса решило мою проблему.

person timotaoh    schedule 20.01.2021