Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the @Autowired interface, which extends CrudRepository, works? I would like to have some insights

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.

like image 589
Pawan Patil Avatar asked Apr 15 '17 08:04

Pawan Patil


1 Answers

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 :

  1. You place the dependency on the EmployeeRepository in your code :

    
    @Autowired 
    private EmployeeRepository employeeRepository;
    
  2. 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.

  3. 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" ?

  4. 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.

like image 194
Ruben Avatar answered Nov 12 '22 22:11

Ruben