Dependency injection (DI) is a form of IOC . Inversion of control IOC is a generic term meaning,transfer of control from main applilcation to a container/framework , for instance rather than having the application call the methods in a framework, the framework calls implementations provided by the application. DI is a form of IOC where the control of the dependencies is inverted from called to callee.
Dependency injection is basically providing the objects that an object needs (its dependencies) by framework/container, instead of having it construct them itself. It's a very useful technique for testing, since it allows dependencies to be mocked or stubbed out. In other words when using dependency injection, objects are given their dependencies at run time rather than compile time .Hence loose coupling between object and depedencies is possible . Dependencies can be injected into objects by many means (such as constructor injection or setter injection). One can even use specialized dependency injection frameworks (e.g. Spring) to do that.
Lets take the example of car and its engine.
public class Car
{
public Car()
{
PetrolEngine engine = new PetrolEngine();
engine.Start();
}
}
public class PetrolEngine
{
public void Start()
{
System.out.println("fuel is petrol");
}
}
The car is instantiating its dependency the engine. This creates a tight coupling between car and its depenency the engine. This is compile time choice and if we want to put a different engine (say electric engine) the code has to be recompiled. In other words in this approach high level Car class is dependent on the lower level PetrolEngine class which violate Dependency Inversion Principle(DIP) from SOLID. DIP suggests that we should depend on abstractions, not concrete classes. So to satisfy this we introduce IEngine interface and rewrite code like below:
public interface IEngine
{
void Start();
}
public class PetrolEngine implements IEngine
{
public void Start()
{
System.out.println("fuel is petrol");
}
}
public class DieselEngine implements IEngine
{
public void Start()
{
System.out.println("fuel is diesel");
}
}
public class Car
{
private IEngine engine;
public Car(IEngine engine)
{
this.engine = engine;
}
public void Run()
{
this.engine.Start();
}
}
Now our Car class is dependent on only the IEngine interface, not a specific implementation of engine. Now, how do we create an instance of the Car and give it an actual concrete Engine class like PetrolEngine or DieselEngine. That's where Dependency Injection comes in.
Car petrolCar = new Car(new PetrolEngine());
petrolCar.Run();
Car dieselCar = new Car(new DieselEngine());
dieselCar.Run();
Here we basically inject(pass) our dependency(Engine instance) to Car constructor. So now our classes have loose coupling between objects and their dependencies, and we can easily add new types of engines without changing the Car class.
DI in spring
Dependency Injection is a important aspect of the Spring framework, through which the Spring container “injects” objects into other objects or “dependencies”.Simply put, this allows for loose coupling of components and moves the responsibility of managing components onto the container.
In spring the annotation @Autowired can be used for DI.
class Laptop
{
@Autowired
HardDrive drive;
}
@Component
class DellHardDrive implements HardDrive
{
}
The above code example shows how to achieve DI in spring. @Component annotation makes this class a spring component. When spring looks at @Autowired annotation, it knows it has to provide an instance . It will look for a matching component.
Scopes
- Singleton
-
@Component //This statement is redundant - singleton is default scope @Scope("singleton") //This statement is redundant public class Engine implements IEengine{ }
- Singleton is default bean scope in spring container. It tells the container to create and manage only one instance of bean class, per container. Prototype scope
-
@Component //This statement is redundant - singleton is default scope @Scope("prototype") public class Engine implements IEengine{ }
- prototype scope results in the creation of a new bean instance every time a request for the bean is made by application code.
-