Как работает интерфейс @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 ответ:
Действительно, уже есть отличный ответ о хранилищах данных Spring, описанный в: как на самом деле реализуются хранилища данных Spring? . Однако, читая ваш вопрос, я думаю, что есть некоторая путаница в отношении того, как работает
@Autowired
. Позвольте мне попытаться дать высокоуровневую последовательность событий:
Вы помещаете зависимость от
EmployeeRepository
в свой код:@Autowired private EmployeeRepository employeeRepository;
Делая шаг (1), вы указываете на пружину контейнер, который в процессе запуска должен найти экземпляр класса, реализующего
EmployeeRepository
, и ввести его в цель аннотации@Autowired
. Я хотел бы здесь подчеркнуть тот факт, что для правильной работы инъекции вы должны иметь экземпляр класса , реализующий требуемый интерфейс в контейнере Spring во время выполнения , а не во время процесса компиляции.Так что теперь логично возникают вопросы: "откуда класс, реализующий
UserRepository
, появляется в контейнере Spring во время его запуска, если мы явно не определили этот класс"?Это был подробный ответ от Oliver comes in: как на самом деле реализованы хранилища данных Spring?. В двух словах, то, что происходит, - это то, что данные Spring во время процесса начальной загрузки контейнера сканируют все интерфейсы репозиториев; создает новые классы (прокси), которые реализуют их интерфейсы; помещает экземпляры этих классов в контейнер Spring, который позволяет
@Autowired
находить и вводить их, как это было бы сделано для любого другого Боба Spring в контейнере.И опять же, этот процесс работает только в том случае, если у вас есть данные Spring, настроенные и правильно настроенные, в противном случае инъекция действительно не удалась бы.
Надеюсь, это поможет.