From the course: Spring: Framework in Depth

The inversion of control (IoC) container

From the course: Spring: Framework in Depth

Start my 1-month free trial

The inversion of control (IoC) container

- [Instructor] The inversion of control pattern is fundamental to the operation of the Spring framework. It is critical for users of the Spring framework to understand not only the benefits of inversion of control and dependency injection in general, but also to understand the consequences of using this pattern. Inversion of control adds a new dimension to how you write your code. The container itself maintains all of the classes including the dependency classes. This is a critical aspect of IoC. While the containers handles the maintenance of these objects, your business logic doesn't have to. Objects are injected at runtime, usually during a startup operation. This allows the container to maintain the objects and hand them as dependencies to other objects within that runtime. An object that accepts these dependencies usually does this through construction of the object itself or through setter injection. This is a topic that can cause some discussion. But the rule of thumb is this: if your class cannot operate without the dependency, it should be injected via constructors. If your class can treat the dependency as optional or can accept multiple but variable concrete instances of the dependency, then it can be injected via setter injection. So let's take a look at traditional dependency management graph, so we can visualize the difference, especially with some kind of complexity. So we will start with a class called main. Now, in the construction of main, you have two dependent classes. So you need to construct those classes when you construct main. However, in constructing one of those dependent classes, you need another class. So you need to construct that as well back up in main. And finally, that class has two dependent classes, so you need to construct those as well when you construct main. So when you're doing the construction of main, you're constructing five additional classes in order to get this dependency graph. So we're now four layers deep of object construction just to create a single class. This level of complexity exists in many Java or any other object oriented language programs that exist today. Now, for the IoC container model, we're going to use the same dependency graph. However this time, we're going to start with the IoC container and our main class. Now the IoC container manages every object in our graph. So once again, main has two dependencies, and instead of constructing them, it takes them as constructor arguments and the IoC container handles that injection at object creation for main. Now once again, the IoC created our dependent class, but that had a dependency. It once again handled the injection via constructor argument, and handed that object to its dependency. Now once again, that object has two dependencies. And just like before, the IoC container hands those dependencies. Now, you may immediately see that we have an order in which our dependencies must be created to make this model work. And with Spring, we don't have to worry about that. As we will see, the framework handles all of that for us, so what you will see is that this complexity actually becomes a simplification, because we only configure these classes once no matter how many times that dependency is used and once we create it, we don't have to worry about it again. So let's take a little time and talk about why this is an important topic when dealing with complex applications. Inversion of control and dependency injection reduce the noise in your code. If you have a class that's used in several places in your application, that becomes even more clear, because you can focus on your business code and not constructing and managing those dependencies multiple times throughout your application. By removing construction of objects within your code, you reduce coupling. You simply consume the objects and they become less coupled to object creation. This becomes even better if your code to interfaces. But more on that in a moment. DI and IoC also reduce the bugs that arise during object creation. We all know how repetitive behavior in code is handled, copy and paste. If a bug exists, you have now copied it into two places. But if you modify that behavior to only one spot, and don't in the other, you still have the bug. By allowing the IoC to handle construction, you can focus on the API contract of your dependencies. This allows interfaces to be dependencies instead of concrete objects. Again, this allows you to have cleaner code that is less coupled to your dependent objects.

Contents