The main concept of Dependency injection - as I understand it - is the practice of "design for interfaces" to make dependent components loosely-coupled of each others. However, I have seen many systems developed using Spring that - in my opinion - violate this concept [ And Spring Container allows that at the syntax level]. I am starting to question my knowledge/understanding of Dependency injection as a concept after seeing such code/implementation.
I regularly see the components auto-wired to each other with their concrete implementation, an example of What I mean:
@RestController
public class MyRestController {
@AutoWired
private MyServiceOne serviceOne;
// .. rest of the code if the rest controller here ...
}
@Service
public class MyServiceOne {
@Autowired
private MyRepository repo;
// rest of code of the service here
}
as you can see, "MyServiceOne" is a concrete class, not an interface, and Spring Framework is OK with that. No "@Bean" method needed to be provided in a "@Configuration" class somewhere to inject the correct concrete class type [ as the @service is already a concrete class].
So, for any change/customization in the service layer [ the injected dependency in the controller], I will have to change the following line in the controller:
@AutoWired
private MyServiceOne serviceOne; //change this to be another service class, or a service class that extends it
and that is NOT loose-coupling! [or is it?] in my opinion, if we are going to use Spring DI that way, it's better NOT to use it at all! a lot of maven/Gradle dependencies and run-time objects are created in the application memory!
I am wondering, is there is something missing in my understanding to How Dependency Injection is as a concept/or how Spring Handle Dependency injection?
appreciate your guidance!
Using an interface usually is a best practice, and you should generally prefer it in your own code (along with constructor injection instead of this field injection), but being absurdly purist about what is allowed would be counterproductive.
As an example, I'm working with Amazon DynamoDB, and I need to inject a DynamoDB
class instance. I'd really prefer to be able to inject an interface, but Amazon's SDK doesn't provide one, and being able to inject the configured instance of the class is still a lot better than injecting nothing.
Similarly, with Spring Boot it's not uncommon to inject @ConfigurationProperties
beans, which are basically struct-like POJOs with no logic. In this case defining an interface would just be a waste of time, but the ability to inject the beans by the (concrete) type is immensely useful.