Как работает интерфейс @Autowired, который расширяет CrudRepository? Я хотел бы иметь некоторые идеи в легком языке


Предположим, что мой интерфейс расширяет CrudRepository следующим образом

 @Repository
    public interface EmployeeRepository extends CrudRepository<Employee, Integer> 
    {
    }

И я использую интерфейс EmployeeRepository в своем классе обслуживания следующим образом

@Service
public class EmployeeService 
{

 @Autowired 
  EmployeeRepository employeeRepository;


 public List<Employee> getAllEmployee()
 {
     List<Employee> listEmp=new ArrayList<Employee>();
     employeeRepository.findAll().forEach(listEmp::add);
     return listEmp;


 }
}

И контроллер следующим образом

@RestController
public class WelcomeController 
{
    @Autowired
    EmployeeService empservice;

    @RequestMapping("/employees")
    public List<Employee> getEmployees()
    {
        return empservice.getAllEmployee();
    }

}

И это дает следующее исключение

Орг.весенняя рамка.зернышки.завод.UnsatisfiedDependencyException: ошибка при создании Бина с именем 'welcomeController': неудовлетворенная зависимость, выраженная через поле 'empservice': ошибка при создании Бина с именем "employeeService" : неудовлетворенная зависимость, выраженная через поле "employeeRepository"

Ошибка очевидна, поскольку интерфейс EmployeeRepository не реализован ни одним классом и

@Autowired  
EmployeeRepository employeeRepository;

Подгружен не удастся, потому что ни один класс реализует employeeRepository.

Тем не менее, я в замешательстве относительно того, как это работает, поскольку каждый код, который я видел на GitHub и учебнике, работает отлично.

Где я ошибаюсь и как @Autowired работает на интерфейсе, который расширяется Грубо говоря, несмотря на то, что ни один класс не реализует его; какое основное правило Автопроводки? То есть, если вы автоматически подключаете какой-либо интерфейс, по крайней мере один класс должен реализовать этот интерфейс, и тогда Autowiring будет успешным.

1 3

1 ответ:

Действительно, уже есть отличный ответ о хранилищах данных Spring, описанный в: как на самом деле реализуются хранилища данных Spring? . Однако, читая ваш вопрос, я думаю, что есть некоторая путаница в отношении того, как работает @Autowired. Позвольте мне попытаться дать высокоуровневую последовательность событий:

  1. Вы помещаете зависимость от EmployeeRepository в свой код:

    
    @Autowired 
    private EmployeeRepository employeeRepository;
    
  2. Делая шаг (1), вы указываете на пружину контейнер, который в процессе запуска должен найти экземпляр класса, реализующего EmployeeRepository, и ввести его в цель аннотации @Autowired. Я хотел бы здесь подчеркнуть тот факт, что для правильной работы инъекции вы должны иметь экземпляр класса , реализующий требуемый интерфейс в контейнере Spring во время выполнения , а не во время процесса компиляции.

  3. Так что теперь логично возникают вопросы: "откуда класс, реализующий UserRepository, появляется в контейнере Spring во время его запуска, если мы явно не определили этот класс"?

  4. Это был подробный ответ от Oliver comes in: как на самом деле реализованы хранилища данных Spring?. В двух словах, то, что происходит, - это то, что данные Spring во время процесса начальной загрузки контейнера сканируют все интерфейсы репозиториев; создает новые классы (прокси), которые реализуют их интерфейсы; помещает экземпляры этих классов в контейнер Spring, который позволяет @Autowired находить и вводить их, как это было бы сделано для любого другого Боба Spring в контейнере.

И опять же, этот процесс работает только в том случае, если у вас есть данные Spring, настроенные и правильно настроенные, в противном случае инъекция действительно не удалась бы.

Надеюсь, это поможет.