Engineering Full Stack Apps with Java and JavaScript
Inversion of Control is a pattern where the controls of dependencies are moved out usually from program components to container. The usual control flow of a program is inverted, and hence it is called so.
For instance, instead of using a new keyword to create an object and setting dependencies, a dependency injection framework (e.g. spring container) will create the object and its dependencies for you at runtime and inject them into your code.
The process of injecting the dependencies of your class from outside of the class is called dependency injection. The dependencies (including transitive dependencies) are usually injected into code by a dependency injection framework like the Spring framework. To make use of this flexibility better, you have to program to abstraction, and allow the framework to inject the actual instance at runtime.
Inversion of control (IoC) may also be done using dependency lookup. Dependency lookup is the looking up of dependencies using container provided services, like a JNDI lookup.
Implicit dependency injection is always preferred over explicit dependency lookup. This is because, the application code will be free of any lookup code which usually depend on container APIs, and hence can be moved across containers.
Primary advantage of inversion of control is that you can change one implementation to another implementation easily if you have also coded to interfaces.
Inversion of Control (IoC) in containers can be through dependency lookup and dependency injection, though IoC is usually understood as dependency injection.
Inversion of Control (IoC) and Dependency Injection (DI) leads to loose coupling. Loose coupling is always desirable.
Dependency injection can be Constructor Injection (injecting through constructors) and/or Setter Injection (injecting through setters).
Setter Injection
Primary advantage of Setter Injection is that it allows re-configuring of the components after its creation.
Disadvantages of Setter injection include:
may leave the object in an incomplete state if all dependencies are not injected before use.
it might not be suitable if the order of invocation of setter methods is important.
Constructor Injection
Primary advantage of constructor injection is that component will be in a consistent state and ready to use immediately after its creation.
Disadvantage of constructor injection include:
We will not be able to reconfigure the component, unless setters are also present.
Constructor injection cannot handle circular dependency whereas setter injection can handle circular dependency: if two objects depend on the other through constructor injection, both objects will not be created as both cannot be created without the other.
If you want to explore more on this topic, please read post written by Martin Fowler on 'Inversion of Control Containers and the Dependency Injection pattern'. Please note that some of the content might even contradict the definitions given above.