Search

Spring Dependency Injection - An Introductory Tutorial / example

This article discusses dependency injection in a tutorial format. It covers some of the newer features of Spring DI such as annotations, improved XML configuration and more.
Dependency Injection
Dependency Injection (DI) refers to the process of supplying an external dependency to a software component. DI can help make your code architecturally pure. It aids in design by interface as well as test-driven development by providing a consistent way to inject dependencies. For example, a data access object (DAO) may depend on a database connection. Instead of looking up the database connection with JNDI, you could inject it. 

One way to think about a DI container like Spring is to think of JNDI turned inside out. Instead of an object looking up other objects that it needs to get its job done (dependencies), a DI container injects those dependent objects. This is the so-called Hollywood Principle, “Don't call us” (lookup objects), “we’ll call you” (inject objects).
 

If you have worked with CRC cards you can think of a dependency as a collaborator, i.e., an object that another object needs to perform its role.
 
Let's say that you have an automated teller machine (ATM) and it needs the ability to talk to a bank. It uses what it calls a transport object to do this. In this example, a transport object handles the low-level communication to the bank.
 

This example could be represented by either of the  two interfaces as follows:
 

AutomatedTellerMachine interface
package com.arcmind.springquickstart;

import java.math.BigDecimal;

public interface AutomatedTellerMachine {
void deposit(BigDecimal bd);
void withdraw(BigDecimal bd);
}

ATMTransport interface
package com.arcmind.springquickstart;

public interface ATMTransport {
void communicateWithBank(byte [] datapacket);
}
Now the AutomatedTellerMachine needs a transport to perform its intent, namely withdraw money and deposit money. To carry out these tasks, the AutomatedTellerMachine may depend on many objects and collaborates with its dependencies to complete the work. 

An implementation of the AutomatedTellerMachine may look like this:
AutomatedTellerMachine implementation:
package com.arcmind.springquickstart;

import java.math.BigDecimal;

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

private ATMTransport transport;

public void deposit(BigDecimal bd) {
...
transport.communicateWithBank(...);
}

public void withdraw(BigDecimal bd) {
...
transport.communicateWithBank(...);
}

public void setTransport(ATMTransport transport) {
this.transport = transport;
}

}
The AutomatedTellerMachineImpl does not know or care how the transport withdraws and deposits money from the bank. This level of indirection allows us to replace the transport with different implementations such as in the following example:

Three example transports: SoapAtmTransport, StandardAtmTransport and SimulationAtmTransport
package com.arcmind.springquickstart;

public class SoapAtmTransport implements ATMTransport {

public void communicateWithBank(byte[] datapacket) {
...
}

}
package com.arcmind.springquickstart;

public class StandardAtmTransport implements ATMTransport {

public void communicateWithBank(byte[] datapacket) {
...
}

}
package com.arcmind.springquickstart;

public class SimulationAtmTransport implements ATMTransport {

public void communicateWithBank(byte[] datapacket) {
...
}

}

Notice the possible implementations of the ATMTransport interface. The AutomatedTellerMachineImpl does not know or care which transport it uses. Also, for testing and developing, instead of talking to a real bank, notice that you can use the SimulationAtmTransport.
Download Spring examples source code

No comments:

Post a Comment