Suppose my interface extends CrudRepository as follows
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>
{
}
and I use the EmployeeRepository interface in my Service class as follows
@Service
public class EmployeeService
{
@Autowired
EmployeeRepository employeeRepository;
public List<Employee> getAllEmployee()
{
List<Employee> listEmp=new ArrayList<Employee>();
employeeRepository.findAll().forEach(listEmp::add);
return listEmp;
}
}
and controller as follows
@RestController
public class WelcomeController
{
@Autowired
EmployeeService empservice;
@RequestMapping("/employees")
public List<Employee> getEmployees()
{
return empservice.getAllEmployee();
}
}
and it gives the following exception
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'welcomeController': Unsatisfied dependency expressed through field 'empservice': Error creating bean with name 'employeeService': Unsatisfied dependency expressed through field 'employeeRepository'
The error is obvious because interface EmployeeRepository is not implemented by any class and
@Autowired
EmployeeRepository employeeRepository;
Autowired will fail because no class is implementing employeeRepository.
Still, I am confused as to how it works as, every code I saw on GitHub and tutorial, works perfectly.
Where am I going wrong and how does @Autowired work on the interface which extends CrudRepository, even though no class is implementing it; which is the basic rule of Autowiring? That is, if you are auto wiring any interface, at least one class has to implement that interface then and then Autowiring will be successful.
Well, there is indeed already a great answer about Spring Data Repositories described in : How are Spring Data repositories actually implemented? . However, when reading your question I believe there is a bit of confusion with regards the way the @Autowired
works. Let me try to give the high level sequence of the events :
You place the dependency on the EmployeeRepository
in your code :
@Autowired
private EmployeeRepository employeeRepository;
By doing step (1) you indicate to the Spring container that during its startup process it should find an instance of the class which implements EmployeeRepository
and inject it into the target of the @Autowired
annotation. I would like here to stress the fact that in order for the injection to work properly you should have the instance of the class implementing the required interface in the Spring container during the runtime and not during the compilation process.
So now a logical questions comes in : "Where from a class implementing the UserRepository
appears in the Spring container during its startup process if we have not explicitly defined that class" ?
Thats were a detailed answer from Oliver comes in : How are Spring Data repositories actually implemented?. In the nutshell what happens is that Spring Data during the container bootstrap process scans for the all repositories interfaces; creates new classes (Proxies) which implement these interfaces; puts instances of those classes into the Spring container which allows for @Autowired
to find and inject them as it would do for any other Spring bean within the container.
And again, these process works only if you have Spring Data set up and correctly configured, otherwise indeed the injection would fail.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With