Some time ago, I applied for a role at a tech consultancy firm. I was required to complete a take-home assignment. The code would then be used during the interview to discuss with the interviewer about my approach. I was surprised when the interviewer mentioned constructor injection and said it was an anti-pattern and I should be using field injection instead. The recommended approach to Dependency Injection is constructor injection, and in this article, we shall see why.

In the following lousy example, SimpleController depends on a SimpleRepository class. We satisfy the dependency by instantiating inside the constructor. This is not a good practice because we have taken over the control. If SimpleRepository also depends on other classes, we must provide these dependencies.

  
class SimpleRepository {  
}  
  
class SimpleController {  
    private final SimpleRepository simpleRepository;  
    
    SimpleController() {      
        this.simpleRepository = new SimpleRepository();   
    }
}  

With Spring, we get inversion of control as Spring will manage the instantiation of these dependencies for us.

@Repository  
class SimpleRepository {  
}  
  
@Controller  
class SimpleController {  
    private final SimpleRepository simpleRepository;  
    
    SimpleController(SimpleRepository simpleRepository) {      
        this.simpleRepository = simpleRepository;   
    }
}  

Three ways to inject dependencies

1. Constructor Injection

The @Autowired is implicit in constructor injection which tells Spring to inject the SimpleRepository into SimpleController.

@Repository  
class SimpleRepository {  
}  
  
@Controller  
class SimpleController {  
    private final SimpleRepository simpleRepository;  
    
    SimpleController(SimpleRepository simpleRepository) {      
        this.simpleRepository = simpleRepository;   
    }
}  

2. Setter Injection

We cannot declare the field as final when we use setter injection. The downside is that it can be modified later.

@Repository  
class SimpleRepository {  
}  
  
@Controller  
class SimpleController {  
    // private final SimpleRepository simpleRepository;   
    private SimpleRepository simpleRepository;  
    
    @Autowired   
    public void setSimpleRepository(SimpleRepository simpleRepository) {      
        this.simpleRepository = simpleRepository;   
    }
}  

3. Field Injection

We are violating the basics of Java. The field is private, yet somehow we injected a dependency into the class. Spring uses reflection to achieve this. Therefore there is a chance that it may be null. We also cannot declare the field as final. Another downside is testability. We are not able to mock the dependency.

@Repository  
class SimpleRepository {  
}  
  
@Controller  
class SimpleController {  
    @Autowired   
    private SimpleRepository simpleRepository;
}  

The argument for using field injection is that the code is cleaner as there is no need for constructor boilerplate code. If I have a class with ten dependencies, the constructor code becomes long and messy. A class with ten dependencies would likely mean that the architecture of your application is not well designed. Consider abstracting some business logic to other places.

The only time when field injection should be used is for writing tests.

@SpringBootTest  
class SimpleControllerTest {  
    @MockBean    
    private SimpleRepository repository;        
    
    @Autowired  
    private SimpleController controller;        
    
    @Test  
    void contextLoads() {        
        Assertions.assertNotNull(repository);        
        Assertions.assertNotNull(controller);    
    }
}  

Conclusion

The downsides of constructor injection are minimal compared to the other ways of dependency injection in Spring. Therefore, it is the recommended approach to dependency injection.