Dependency injection and inversion of control in Spring
What makes the Spring framework a framework? Inversion of control is the answer.
IoC is what sets apart frameworks such as Spring, Flask or Angular from reusable libraries that simply provide functions that developers can call.
What is inversion of control?
Inversion of control is a simple design principle that encourages developers to keep their core business logic clear and concise, and also externalize complex operations such as lifecycle management, component configuration and low-level system interactions. IoC frameworks including Spring and Angular manage this externalization.
Benefits of inversion of control
Along with keeping a developer's code clean, IoC frameworks provide a variety of other benefits, including the following:
- Loosely couple the code and external components.
- Externalize complex logic to specialized frameworks.
- Improve time to market, as developers' focus is to deliver features.
How do IoC and dependency injection work?
To understand why IoC and dependency injection typically go hand in hand, think about the following two objectives of IoC:
- Keep business logic clean and concise.
- Loosely couple code from external resources.
An IoC framework manages the lifecycle of the components a developer writes. That includes creation, provisioning and even garbage collection. However, there are times when the code requires access to one of the classes managed by the Spring IoC container. How does one access it?
One approach is to access the Spring IoC container directly. However, this approach conflicts with the aforementioned goals of clean code and loose coupling. The application would be cluttered with complex code when it interacts with the IoC container, and the business logic would become tightly coupled to the Spring framework.
This is where dependency injection comes in.
Spring dependency injection
If the Spring IOC container manages two components in an application and one depends on the other, simply ask Spring to fulfill that dependency at runtime. The semantics that enable this dependency injection occur outside the code, keeping the code clean and loosely coupled from the framework.
In the following example, the @Autowired
annotation tells the Spring IoC container where to perform dependency injection.
@Component
class Taxi {
@Autowired
PriceMeter priceMeter;
}
@Component
class PriceMeter {
double price;
}
In this example, the Taxi requires a PriceMeter. In programming context, that means the Taxi
class has a dependency upon the PriceMeter
class.
With dependency injection, this requirement is resolved at runtime, and concise annotations are the only direct reference to Spring. Furthermore, these @Component
references could be completely removed if a Spring XML file or a Spring @Configuration
class was used instead.
That's the basics of inversion of control and dependency injection in Spring. IoC is a simple design principle that promotes clean code and loose coupling, while dependency injection uses an IoC framework such as Spring with no direct references to it in the code.
Cameron McKenzie has been a Java EE software engineer for 20 years. His current specialties include Agile development; DevOps; and container-based technologies such as Docker, Swarm and Kubernetes.