kentoh - Fotolia
Meaning of inversion of control in Spring and Java: IoC explained
What is inversion of control, and why has inversion of control in Spring and Java become such a core development concept?
The insurgence of Spring Boot as the go-to framework for microservices development has spawned renewed interest in the fundamentals of the Spring framework. Folks are particularly interested in the dependency injection pattern and the meaning of inversion of control, or IoC.
Spring dependency injection and the inversion of control principle are distinct and separate, though they are often combined. As such, many confuse the ideas behind a dependency injection pattern with the meaning of inversion of control. For clarity's sake, let's view both topics separately, then examine where the technologies intersect and even complement each other.
More about Contexts and DI
TheServerSide has been updating its resources in terms of the Spring framework, Java EE contexts and various different approaches to inversion of control (IoC) and dependency injection (DI). Check out these newer resources on the topic:
- A modern Inversion of Control example in Java using Spring
- Drawbacks to IoC problems and how to solve inversion of control problems
- How IoC works in Google Guice
- Spring MVC Java web development with Spring Boot
- Spring IoC vs. Google Guice's inversion of control approach
- Getting started with Google Guice
- Getting started with the Spring IoC container
The meaning of inversion of control in Java
We can define the word inversion as a reversal of the natural order. When programming in Java, the natural order is to declare variables and then initialize those variables with instances of objects you create. Here's a simple example:
Question q1 = new Question();
There is no inversion of control pattern in this example. Here, we've named the variable q1; it is of type Question, and one could create an instance by calling the constructor and using the new keyword: new Question().
Inversion of control explained
If we were to apply the inversion of control pattern to the above example, the developer could not use the new keyword and call the constructor of the Question class.
Instead, when needed, a magical and mysterious black box -- often referred to as the IoC container -- will provide instances of the Question class.
Question q1 = MysteriousBlackBox.getInstance(Question.class);
Inversion of control in Spring
The use of the MysteriousBlackBox class in the previous line of code may seem silly, but it's actually not.
If a developer introduces this inversion of control example with the Spring framework, the actual code would look as follows:
Question q1 = context.getBean(com.mcnz.ioc.explained.Question.class);
When you implement inversion of control in Spring, call the IoC container that provisions instances the ApplicationContext, not MysteriousBlackBox, even though it behaves the same. An IoC container should be exactly that -- a black box with internal workings that a software developer need not be concerned about. That is the fundamental meaning of inversion of control in Java.
Benefits of inversion of control
The benefits of inversion of control in Spring and Java are a developer can maintain the creation, configuration, provisioning and lifecycle of all container-managed objects separately from the code where they are referenced. As such, IoC eases the software developer's concern about these aforementioned activities.
If the configuration for the database connection changes, a developer only needs to change the settings in the IoC container, not rewrite the code. And if an instance of a class gets cached and pooled, the IoC container can also take care of this. Furthermore, if an application uses only one instance of a class, an IoC container can provide this behavior, as well.
The application also becomes more flexible and adaptable, especially if the application pulls instances of interfaces from the IoC container. At any point, the maintainers of the IoC container can provide a new implementation of a class, or even a specialized subclass, when they request an instance. An IoC container could provide a new and more efficient implementation at runtime. This can all be performed by configuring the IoC container and leave the bulk of the codebase alone. If the change is undesirable, the IoC container can easily roll it back.
IoC testing
Perhaps the most important feature of an inversion of control container is it helps facilitate Agile practices, such as test-driven development. During testing phases, the IoC container can provide mock objects or stub classes to the running program. This can help developers do testing when external systems, such as databases or message queues, are unavailable. It can also provide instances that trigger exceptions or simulate curious corner cases that simulate how the application will respond when problems arise. There are plenty of reasons why inversion of control in Java is such a popular design pattern. The manner in which the IoC pattern works with application testing cycles is arguably the most important one.
The IoC pattern is a way of reversing the traditional approach to create and initialize Java objects. Rather than create objects directly within their code, developers ask a third party, such as the Spring container or the Java EE context, to provide instances instead. It allows objects to be centrally managed, easily configured and integrated into testing cycles, all while simplifying the life of the software developer introducing core functionality. No wonder the inversion of control principle is so omnipresent in the world of modern software development.