Spring Dependency Injection and Inversion of Control

  • Dependency Inversion Principle (DIP) is a design principle which is in some ways related to the Dependency Injection (DI) pattern. The idea of DIP is that higher layers of your application should not directly depend on lower layers. Dependency Inversion Principle does not imply Dependency Injection. This principle doesn’t say anything about how higher layers know what lower layer to use. This could be done as shown below by coding to interface using a factory pattern or through Dependency Injection by using an IoC container like Spring framework, Pico container, Guice, or Apache HiveMind.

The Dependency Inversion Principle (DIP) states that

  • High level modules should not depend upon low level modules. Both should depend upon abstractions.
  • Abstractions should not depend upon details. Details should depend upon abstractions.

When this principle is applied, the higher level classes will not be working directly with the lower level classes, but with an abstract layer. This gives us the flexibility at the cost of increased effort.Here are some code snippets for DIP.

Firstly define the abstraction layer.

package principle_dip2; 
public interface AnimalHandler {
 public abstract void handle( ); 
}
package principle_dip2;
public interface AnimalHelper 
{
public abstract void help( );
}}

Now the implementation that depends on the abstraction as opposed to the implementation.

package principle_dip2;
public class CircusService {
AnimalHandler handler;
public void setHandler(AnimalHandler handler) {
this.handler = handler;
}
public void showStarts( ) {
//code omitted for brevity
handler.handle( );
}
}
package principle_dip2;
public class TigerHandler implements AnimalHandler{
AnimalHelper helper;
public void setHelper(AnimalHelper helper) {
this.helper = helper;
}
public void handle( ){
//...
helper.help( );
//...
}
}
package principle_dip2;
public class TigerHelper implements AnimalHelper{
public void help( ){
//......
}
}
  • Dependency Injection (DI) is a pattern of injecting a class’s dependencies into it at runtime. This is achieved by defining the dependencies as interfaces, and then injecting in a concrete class implementing that interface to the constructor. This allows you to swap in different implementations without having to modify the main class. The Dependency Injection pattern also promotes high cohesion by promoting the  Single Responsibility Principle (SRP), since your dependencies are individual objects which perform discrete specialized tasks like data access (via DAOs) and business services (via Service and Delegate classes) .
  • The Inversion of Control Container (IoC) is a container that supports Dependency Injection. In this you use a central container  like Spring framework, Guice, or HiveMind, which defines what concrete classes should be used for what dependencies throughout your application. This brings in an added flexibility through looser coupling, and it makes it much easier to change what dependencies are used on the fly. The basic concept of the Inversion of Control pattern is that you do not create your objects but describe how they should be created. You don’t directly connect your components and services together in code but describe which services are needed by which components in a configuration file. A container (in the case of the Spring framework, the IOC container) is then responsible for hooking it all up. Applying IoC, objects are given their dependencies at creation time by some external entity that coordinates each object in the system. That is, dependencies are injected into objects. So, IoC means an inversion of responsibility with regard to how an object obtains references to collaborating objects.

The real power of DI and IoC is realized  in its ability to replace the compile time binding of the relationships between classes with  binding those relationships at runtime. For example, in Seam framework, you can have a real and mock implementation of an interface, and at runtime decide which one to use based on a property, presence of another file, or some precedence values. This is incredibly useful if you think you may need to modify the way your application behaves in different scenarios. Another real benefit of DI and IoC is that it makes your code easier to unit test. There are other benefits like promoting looser coupling without any proliferation of factory and singleton design patterns, follows a consistent approach for lesser experienced developers to follow, etc. These benefits can come in at the cost of the added complexity to your application and has to be carefully manged by using them only at the right places where the real benefits are realized, and not just using them because many others are using them.

Note: The CDI (Contexts and Dependency Injection)  is an attempt at describing a true standard on Dependency Injection. CDI is a part of the Java EE 6 stack, meaning an application running in a Java EE 6 compatible container can leverage CDI out-of-the-box. Weld is the reference implementation of CDI.