Background
Before we proceed with how dependency injection works in Spring lets see what dependency injection actually is and why is it so important.
Consider a simple example. Lets say we are designing a Cricket game. How will it's class look like?
You will have a Cricket class that will probably have Bat class and Ball class.
public class Cricket { private Bat bat; private Ball ball; public Cricket() { bat = new Bat("MyBat1") ; ball= new Ball("MyBall1") ; } public void play() { bat.play(); ball.play(); } }
How would you play cricket? Probably something like
public class Main { public static void main(String args[]) { Cricket cricket1 = new Cricket(); cricket1.play(); } }
What do you think about above code -
- It is tightly coupled. If you device to change your Bat or Ball you have to write a new Cricket instance.
- It will also be very difficult to test. There can be any type of Bat or Ball and each test your need new Cricket instance.
This is where dependency injection comes into picture. Now consider your cricket class as follows.
public class Cricket { private Bat bat; private Ball ball; public Cricket(Bat bat, Ball ball) { this.bat = bat; this.ball = ball; } public void play() { bat.play(); ball.play(); } }
and you play like
public static void main(String args[]) { Bat bat1 = new Bat("MyBat"); Ball ball1 = new Ball("MyBall"); Cricket cricket1 = new Cricket(bat1, ball1); cricket1.play(); Bat bat2 = new Bat("MyNewBat"); Ball ball2 = new Ball("MyNewBall"); Cricket cricket2 = new Cricket(bat2, ball2); cricket2.play(); }
If you notice you can create and use any type of bat and ball and play cricket with it. All of it is done at runtime. So essentially you are injecting Bat and Ball dependencies into your Cricket object.
Also notice the problems we faced with earlier code are vanished
- Code is now decoupled. You can use any Bat and Ball to play cricket.
- Testing has also becomes very easy as you can now mock your Bat and Ball objects and test your cricket.
There are two types of dependency injection
- Constructor based dependency injection
- Setters based dependency injection
public class Cricket { private Bat bat; private Ball ball; public Bat getBat() { return bat; } public void setBat(Bat bat) { this.bat = bat; } public Ball getBall() { return ball; } public void setBall(Ball ball) { this.ball = ball; } public void play() { bat.play(); ball.play(); } }
and you play like
public static void main(String args[]) { Bat bat1 = new Bat("MyBat"); Ball ball1 = new Ball("MyBall"); Cricket cricket1 = new Cricket(); cricket1.setBat(bat1); cricket1.setBall(ball1); cricket1.play(); Bat bat2 = new Bat("MyNewBat"); Ball ball2 = new Ball("MyNewBall"); Cricket cricket2 = new Cricket(); cricket2.setBat(bat2); cricket2.setBall(ball2); cricket2.play(); }
Simply putting
"Dependency injection is basically providing the objects that an object needs (its dependencies) 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."
That's the dependency injection in general. Now lets come to Spring dependency injection.
Spring Dependency Injection
In Spring dependency injection Spring container instantiates and injects dependencies in your instance (also called beans) based on the dependency type or name (more on this later) rather that you instantiating and injecting it yourself.
Lets see how spring DI works in case of our above code.
- Setter DI
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="myBat" class="Bat"> <bean id="myBall" class="Ball"> <bean id="cricket" class="Cricket"> <property name="bat" ref="myBat"/> <property name="ball" ref="myBall"/> </bean> </beans>
Above bean definition uses setter DI. Spring container scans beans and automatically injects dependencies in it. You can also use
- Constructor based DI
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="myBat" class="Bat"> <bean id="myBall" class="Ball"> <bean id="cricket" class="Cricket"> <constructor-arg ref="myBat"/> <!-- constructor argument order should be same--> <constructor-arg ref="myBall"/> </bean> </beans>
Notes :
- For values as dependency (like simple String) you can do <property name="brand" ref="MRF"/>
- Instead of using property tag you can also use p namespace - <bean id="cricket" class="Cricket" p:brand="MRF" p:bat-ref="myBat" /> (don't forget to add the namespace)
- Also note p namespace does not have any schema reference.
Aurowiring
Instead of explicitly providing dependencies to be injected you can autowire them. One simple example is autowiring by type. In this case Spring container will look for bean of dependency type among all beans and inject it. However note if more than one type of such bean exist this will fail.
- autowire is an attribute in bean tag with following possible values.
Another interesting aspect is spring DI using annotations and component scan. Instead of specifying beans you can directly use annotations and ask spring framework to scan those and autowire. You can see the same in next post -
NOTE : Dependency injection and IoC (Inversion of control) are words used interchangeably. Both mean dependencies are injected rather that created itself by the object which needs the dependencies.