Dependency Injection - An Introductory Tutorial
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.
ArcMind Inc., Rick's employer, offers Spring Framework training and consulting as well as JSF, GWT, JPA and more
- Login or register to post comments
- 24709 reads
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)










Comments
dzoneCody replied on Tue, 2008/11/11 - 8:40am
Very nice article,
One of my biggest obstacles has been grasping DI conceptionally. I think you did a good job in showing the "tutorial" perspective of DI. Can't wait to see more...
Rick Hightower replied on Thu, 2008/11/13 - 12:09pm
Jakob Jenkov replied on Tue, 2008/11/11 - 2:55pm
Hi Rick,
I just browsed the article quickly. Seems you have spent a long time putting this piece together! Kudos to you!
If I may comment a bit on the title, I think it is perhaps slightly mis-leading. This article, though definately useful, is more of a "Dependency Injection with Spring"-tutorial. Some of the concepts are unique to Spring, and the configuration examples definately are too. But readers new to dependency injection could be lead to believe, that dependency injection is only something you can do with Spring. But there are Pico, Guice and Butterfly Container too, among others.
You do mention Spring early on page 1, so I guess the "mislead" reader is quickly corrected. Anyways, with frameworks growing as huge as Spring is, it is nice with "getting started / introductory" articles like this one.
I too wrote a tutorial on dependency injection, but my tutorial tries to explain the concept a bit more detached from any specific DI container (yet it shows examples using Butterfly DI Container). In the end of this tutorial I also explain when and when NOT to use dependency injection (according to my opinion / experience).
Rick Hightower replied on Tue, 2008/11/11 - 3:05pm
in response to: jj83777
digitalcorndawg replied on Tue, 2008/11/11 - 3:05pm
hovo73 replied on Tue, 2008/11/11 - 3:06pm
cmathias replied on Tue, 2008/11/11 - 3:09pm
Nice article Rick. I love the DI concept, but I struggled with it at first, as I imagine most developers do who have been authoring more traditional workhorse code. I find it amazing how using things like Spring let me get down to business...most of my code these days actually does only what it needs to do rather than taking twenty lines to set up the three important ones.
I think it's great that heavyweights like yourself that really 'get' this stuff take the time to turn back, and teach the rest who are lagging.
I would disagree with Jakob's observation as I feel you did mention alternatives more than once. (though yes, your samples are Spring). Spring has become a monster, but from my experiences so far, is still the sharpest knive in the drawer.
Keep it up Rick - the one I'm personally waiting for is the AspectJ introduction (specifically tapping cut points in compiled libraries). Can you just DI that into my head please?
tac replied on Tue, 2008/11/11 - 3:21pm
excellent concrete example of using dependency injection. I am a long-time Spring user but there were several useful pieces of information on some of the newer features. I will definitely add the 'p:' tags to my toolkit. Thanks,
-tom
Paul Hixson replied on Tue, 2008/11/11 - 3:24pm
Jakob Jenkov replied on Tue, 2008/11/11 - 3:59pm
Walter Bogaardt replied on Tue, 2008/11/11 - 4:38pm
Great explanation. I was wondering what happens to the role of the applicationContext with all the annotations. It was one of those todo things to look at when I had some cycles, and you cleared it up in a few lines.
I'd like to see something on the spring annotations features like @Bean and javaconfig, and spring or DI in the web world of servlets, jsf, jsp. Keep up the good articles.
Steven replied on Wed, 2008/11/12 - 6:41am
great read, but it feels like it missed a key part: actually integrating spring into an app.
i.e. starting it up, adding the context/listener to web.xml or something similar like even using the bean factory.
Stuart Halloway replied on Wed, 2008/11/12 - 9:15am
Hi Rick,
Responding per your request for comments. I found the tutotial easy-to-follow, but I don't want to follow where it goes. :-) I think DI is overrated, and both XML and Annotations are bad ways to do it. If a team is committed to DI, I would recommend a Groovy, JRuby, or Clojure based DSL.
Cheers,
Stuart
johnfryar replied on Wed, 2008/11/12 - 9:53am
You have particular skill with examples. The examples you provide here, as with your JSF tutorial on developerworks, are USEFUL and clearly illustrate some key concepts. The images you use to highlight how the xml is related to the java code and how the annotated classes related one-to-another are top-notch. You could probably expand that approach into a book and it would be very helpful to both newbies and experience Spring developers.
I agree with Jakob that the title is misleading. This really isn't about DI so much as it is about DI using Spring. That being said, it's a fantastic article for anyone looking for an introduction to DI using Spring.
I look forward to the follow-up articles.
Solomon replied on Wed, 2008/11/12 - 2:06pm
This is a follow up to your linkedIn question:
I'd like to revise this question a bit to: "When should you annotate a class with Injection configuration, and when should you externalize the Injection configuration?"
IMHO, the more generic question is key on how you should think about DI. 80-90% of the time you can annotate a class with DI info. The types of annotations you're adding are "I need an instance of X class injected here" (for example Spring's @Autowired and @Required, JEE's @Resource and Guice's @Inject), "I am available for use" (Spring's @Component/@Service/@Controller/@Repository, JEE's @Stateless/..., and Guice's @ImplementedBy/@Singleton/...), and "I need/am a specific instance of X class/interface" (Spring's @Qualifier, and Guice's @BindingAnnotation).
There are quite a few reasons for the other 10-20% of cases that don't make sense, and for those, DI configuration needs to be put somewhere else, for example in Spring XML, Spring JavaConfig or Guice Modules/Producers. Some of the reasons are:
1) The class is defined in a location that you don't have control over, such as a vendor jar.
2) The class encapsulates an environmental configuration, such as setting up a DataSource or Hibernate configuration
3) You need more than one instance of the same exact class
Some cases have a 100% need to be externalized (for example, database and hibernate). However, there are plenty of cases that are pretty tricky to either categorize or implement.
One quick example of a borderline common case is a Spring @Controller. I often configure MVC Controllers with a JSP file or Tile that I'd like to use. You can do that by injecting a String value (with a Qualifier "mySuccssView") into the controller; however, Spring doesn't let you use the @Autowired annotation, you have to use JEE's @Resource annotation, or use XML. By the way, the definition of the mySuccssView in Spring XML took 3 lines of code!!! Anyway, I was using WebSphere 6.1, and had to opt out of the @Resource because of classpath issues, so I had to use the XML config. The problem with the XML config is that @Controller servers two purposes: 1) defining a Role in the system, 2) defining the class as "I am available for use in a DI use" as part of classpath scanning and default autowiring. I wanted to set the value the value in XML, therefore the classpath scanning part of #2 was out of the question. To do that, I had to customize the component scanning with a Spring "context:exclude-filter."
The point of that example is that there are still plenty of gotchas that need to be ironed out. Guice is slightly ahead of Spring on those kinds of annotation gotchas. One of the most seemingly obvious abilities that Guice has is the import of key/value pairs into the module (a.k.a. "application context") as seen in this thread in the Guice News Group.
There's a lot more to this topic, but I hope that I've she some more light on this esoteric subject.
jordanz replied on Wed, 2008/11/12 - 5:42pm
Solomon replied on Wed, 2008/11/12 - 7:22pm
in response to: jordanz
Here we go again. This argument is so 2004. I assume that you've read good old Martin Fowler's article on the subject.
DI moved away from Singletons and JNDI lookups. IHMO, DI's been a great boon for the quality and clarity of my code base. XML and annotation aren't code, they are indeed declarative configuration and possibly meta-programming.
You are correct. The term "Configuration" does apply. Usually I think about "Configuration" in the context of environment related setup. DI does make environmental configuration a lot simpler. However, it also adds in the ability to separate out how a particular class does its work and participates with other classes from how that class is exposed and how that class finds instances of other classes.
Yeah, at the end of the day DI is "Configuration", but its configuration that inherently replaces the code you as a developer have to write for the types of things covered by Creational and Structural Design Patterns.
jordanz replied on Wed, 2008/11/12 - 7:46pm
in response to: sduskis
I've read most articles on the subject. Yes, the counter-arguments have been going on for a long time. That doesn't mean that the subject is settled.
Solomon replied on Wed, 2008/11/12 - 8:30pm
in response to: jordanz
I've read most articles on the subject. Yes, the counter-arguments have been going on for a long time. That doesn't mean that the subject is settled.
[/quote]You're right. The subject of DI is not settled yet. But dismissing it as "just configuration" and something that "was done in software practice for years" doesn't seem to do it justice. We mortals do need simple phrases for complex concepts that DI solves like dependency management, environmental configuration and separation of concerns. There are other methodologies of solving those same needs. There are also different imlementations of DI that have plenty of merit.
With that said, comments like "Why not call this what we've always called this: Configuration. Everyone knows what that is." don't seem to lead the direction of the communal conversation towards "settling" the subject.
jordanz replied on Wed, 2008/11/12 - 9:43pm
in response to: sduskis
Actually, I somewhat agree with you. Depenency Injection, however, is an unnecessarily obscure term. When I first heard I had no idea whatsoever what it meant. Automated Configuration is more descriptive. The name of the concept should give a clue as to the content of the concept. Having such an abstract name has allowed DI to mean whatever anyone wants it to mean.
Solomon replied on Thu, 2008/11/13 - 10:06am
in response to: jordanz
Actually, I somewhat agree with you. Depenency Injection, however, is an unnecessarily obscure term. When I first heard I had no idea whatsoever what it meant. Automated Configuration is more descriptive. The name of the concept should give a clue as to the content of the concept. Having such an abstract name has allowed DI to mean whatever anyone wants it to mean.
[/quote]
DiP defines how objects interact with each other and that an object that encapsulates some behavior (DAO, service, UI and etc) should never (or rarely) look up or instantiate another behavior-driven dependency. Those dependencies can be either it another object or some configuration setting. DiP says that in order to get those dependencies, some external assembly system (either a framework, or hand-coding) should assemble the application and "inject" specific dependencies as needed.
In other words, you can adhere to the DI Principle without any configuration. It's the Dependency Injection Frameworks that use configuration to create a solution that adheres to DiP.
ravihasija replied on Thu, 2008/11/13 - 11:23am
This is a great article. Led by example, and not dry by just providing theory. Simple, yet beautiful. Kudos to you for creating this. I have a firm grasp of what Spring and DI (in general) is.
I would love to have such articles on other topics like Hibernate, EhCache, Struts, EJB, JSP, etc to name a few. Probably they are already out there on this website. If not then, something to consider ;-)
Thank you so much!
Sincerely,
Ravi
Rick Hightower replied on Thu, 2008/11/13 - 12:10pm
Rick Hightower replied on Thu, 2008/11/13 - 2:35pm
in response to: ravihasija
Thanks Ravi. I really appreciate the positive feedback. It really helps. Thanks.
Bruno Sofiato replied on Fri, 2008/11/14 - 6:33pm
Cool article.
I personally don't like the current annotation usage model spread on the majority of the frameworks, guys configuration isn't meta-data. Annotations IMHO should be used to express semantical information within the code itself. The @Required annotations got it right. The ATMTransport is required by the AutomatedTellerMachineImpl class, thats an implementation detail of that class, the @Required is expressing a semantical info.
The @Autowired and the @Qualifier on the otherside are expressing config details. They are linking an property value to an named instance on the bean container. Should a class know which named instances will be injected on it's instances ? I think it should not.
Rick Hightower replied on Fri, 2008/11/14 - 11:08pm
in response to: Bruno Sofiato
Bruno Sofiato replied on Sat, 2008/11/15 - 10:42am
in response to: rhightower
Yes, some objects were made to collaborate with others, but maybe the property declaration would provide this kind of info.
I agree that annotations are a popular aproach these days, maybe it's a consequence of this grudge against XML based configuration that is wildspread among the Java developer's ranks.
Just my 2 cents.
William Willems replied on Mon, 2008/11/17 - 5:54am
nitin pai replied on Mon, 2008/11/17 - 10:13pm
Rick - Thanks a ton. This timing of this article has been perfect to match with my intentions. I wanted to make my team understand the concepts of Spring such as DI, IOC, AOP etc. And you have just eased out my work since I do not have to compile the articles myself. This article is simply to the point.
Eagerly waiting for your further articles on Spring features. And if you require any help just let me know. I am on the same track too :)
george.jiang replied on Tue, 2008/11/18 - 9:43pm
The best introduction to Spring 2.5 DI. Better than those published Spring books.
Rick, when will the intoduction article to Spring AOP be out? Thanks.