- Details
- Written by Nam Ha Minh
- Last Updated on 04 July 2019   |   Print Email
This Java tutorial will help you understand the key concepts of dependency injection, step by step through simple code example - easy to understand and follow.So, what is dependency injection?It’s difficult to understand dependency injection in few sentences, so it’s better to begin with some code example.Normally, a class depends on another class to do some work, for example:
public class ClientA {
ServiceB service;
public void doSomething() {
String info = service.getInfo();
}
}Here, class
ClientA uses class
ServiceB which is written as below, for example:
public class ServiceB {
public String getInfo() {
return "ServiceB’s Info";
}
}The class
ClientA is said to be dependent on the class
ServiceB, and
ServiceB is called a
dependency of
ClientA. This kind of dependency is very trivial in programming. However, when the application’s code gets bigger and more complex, the hard-coded dependency among classes introduces some drawbacks:
- The code is inflexible - it’s hard to maintain and extend as when a class permanently depends on another class, change to the depending class my require change to the dependent class. And it’s impossible to change the depending class later without updating and re-compiling the code.
- The code is hard for unit testing because when you want to test only the functionalities of a class, you have to test other depending classes as well.
- The code is hard for reuse because the classes are tightly coupled.
Therefore, dependency injection comes to address these drawbacks, making the code more flexible to changes, easy for unit testing and truly reusable. Then, how dependency injection works?First, interfaces are used to define the types of the classes so its implementation can be changed later. For example, with the above code - the interfaces
Client and
Service are introduced:
public interface Client {
void doSomething();
}
public interface Service {
String getInfo();
}
Then the
ServiceB class becomes an implementation of
Service as below:
public class ServiceB implements Service {
@Override
public String getInfo() {
return "ServiceB's Info";
}
} Then it’s possible to have different implementations of
Service, for example
ServiceC and
ServiceD:
public class ServiceC implements Service {
@Override
public String getInfo() {
return "ServiceC's Info";
}
}
public class ServiceD implements Service {
@Override
public String getInfo() {
return "ServiceD's Info";
}
} And the class
ClientA is now implementing the
Client interface and it uses the
Service interface instead of a concrete class - the actual
Service’s implementation is “
injected” to this class via its constructor -
constructor injection, as shown below:
public class ClientA implements Client {
Service service;
public ClientA(Service service) {
this.service = service;
}
@Override
public void doSomething() {
String info = service.getInfo();
}
} The class
ClientA is now not depending on any specific implementations of
Service. Instead of creating an instance of dependent class directly in
ClientA, the dependency injection container or framework is now responsible for creating that instance and inject it to the class
ClientA via its constructor. For example:
Service service = new ServiceB();
Client client = new ClientA(service);
client.doSomething();
Here, an implementation of
Service is
ServiceB is created and passed to
ClientA, which is not aware of the actual implementation it is using.
ClientA only knows that the injected object is of type
Service.Besides constructor injection,
setter injection is used to pass the depending object to the dependent one. Add the following setter method in the
ClientA class:
public void setService(Service service) {
this.service = service;
}Then we can change to different
Service’s implementation e.g.
ServiceC like this:
((ClientA) client).setService(new ServiceC());
client.doSomething();
That’s a Java code example about dependency injection. Note that we write the code to create and inject the dependencies manually. In practice, a dependency injection container/framework like Spring will do the wiring automatically. You just declare the dependency information via XML file or annotations in Java classes, and the framework manages the dependencies for you.
ConclusionDependency injection is a technique that allows the client code to be independent from the services it is relying on. The client does not control how objects of the services are created - it works with an implementation of the service through interface. This is somewhat in inverse to trivial programming so dependency injection is also called
inversion of control.It makes the code more flexible, extensible, maintainable, testable and reusable - thus dependency injection is very popular in modern programming. In Java, dependency injection is supported since Java EE 6 - called
CDI (Contexts and Dependency Injection). And the Spring framework is based on dependency injection, as well as other frameworks like Google Guice and Play.
Related Dependency Injection Tutorials:
Other Java Coding Tutorials:
About the Author:
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on
Facebook and watch
his Java videos on YouTube.
Add comment
Comments
Thanks
The difference here is the use of interface in service classes - not concrete class. So the container or injector can put any real implementations.
that does not use interfaces at all and still talks about loosely coupled.
Does that mean DI cannot be implemented without using interfaces ?