This article is the first in a series of articles that will look briefly at a number of dependency injection (‘DI’) frameworks, and will try to compare them by implementing some fairly standard DI constructs. The articles will consider both Java and .Net frameworks. The selection of frameworks will not be particularly scientific or comprehensive: they are simply the frameworks I have played with at various times. In particular no DSL-based frameworks will be examined.
The articles will also give a general introduction into how different dependency injection frameworks work.
The articles will assume that you know what dependency injection is and why you would want to use it. If you want a basic explanation of dependency injection see Martin Fowler’s original article on the subject. Also I have written about it before.
I’ll start with a brief discussion of why I decided to look at DI frameworks in this way.
Motivation: Problems with XML Configuration of DI Frameworks
In recent years dependency injection frameworks have gone from being something unusual to being part of the mainstream. In particular, in the Java world the Spring framework has become very popular (although Spring is more than just a dependency injection container).
Traditionally dependency injection containers have been configured using XML configuration files. This is still the most common way of configuring Spring, for example, and is the only way of configuring Spring.Net. However there are a number of problems with the standard XML configuration used in these frameworks:
- We have to learn a new XML syntax just to instantiate our objects (admittedly in the case of both the Spring and Spring.Net frameworks this is fairly straightforward).
- We have very little compile-time support for identifying errors in the XML (almost none in the case of Spring.Net and Visual Studio).
- In particular we use string identifiers for objects. These are easily misspelt, and often the spelling mistake will only manifest itself as a runtime error.
- On any large project the XML can easily get huge and unwieldy, and it can become difficult to debug problems with it.
The last of these is probably the most problematic: big Spring projects aren’t very easy to maintain.
I’m sure anyone using these frameworks will have seen the case where an exception gets thrown when configuring the container, but it’s then hard to work out where the object throwing the exception was being instantiated and why it isn’t set up correctly. The reason that this is difficult, of course, is that we can’t debug the XML configuration by single-stepping through it. We have good runtime debug support through our IDEs for Java or C# code, but none for XML.
Motivation: Alternative Approaches to XML Configuration in Newer DI Frameworks
In recent years there has been a move away from extensive XML configuration in general. I think in part we can thank Ruby on Rails for this, with its heavy emphasis on ‘convention over configuration’.
The ability to configure DI frameworks through code rather than through XML has been around a long time. However, there are currently some new(ish) approaches that seem to promise to deal with the XML problems above:
- Spring itself has JavaConfig (now being incorporated into ‘core’ Spring).
- Microsoft’s Unity DI container has powerful configuration options through code (although it supports XML configuration as well).
- Google’s Guice framework doesn’t use XML at all. Indeed one of Guice’s goals was to remove the use of ‘error-prone, refactoring-averse string identifiers’ in XML configuration.
So this series of articles started as an attempt to assess whether any of these approaches actually solved the problems with XML configuration of DI frameworks described above. I also wanted to look at whether you really need a formal framework at all to use dependency injection effectively: certainly many in the Ruby community claim that they don’t need a DI framework, including one guy who’d actually written a Ruby DI framework and then decided it was a waste of time. It’s true that Ruby does have some dynamic construction options that make it different from Java or C#, but it’s still an object-oriented language.
Also I’d had a look at Spring JavaConfig before starting this series of articles. JavaConfig gives you a smart way of configuring your DI container in code. What’s more the code is very like the ordinary code you might write to configure objects if you weren’t using a framework. It again made me wonder why we need a formal DI framework at all, and whether there’s a DI ‘pattern’ you could use instead. I’ll discuss this in more detail later.
The following frameworks will be examined in this series of articles:
Java: Spring (XML), Spring (JavaConfig), Google Guice
.Net (C#): Spring.Net, Unity (code), Unity ( XML), Composite Application Block (CAB ObjectBuilder)
I will also look at using dependency injection but NOT using a framework; just coding by hand: see the comments at the end of the preceding paragraph.
This article has briefly discussed the motivation for looking at a number of dependency injection frameworks. Part two of this series of articles will look in detail at the tests to be performed on the various frameworks mentioned above.