I have previously tried explaining Dependency Injection and how it can be beneficial to any project. This leads us to an important question about whether to use a framework or to do injection manually. Using a framework all the time may not provide you with additional control, rather at times it may further complicate the code. On the other hand implementing dependency injection manually can sometimes become more time consuming and painful. So how do we actually choose?
Both approaches have their pros and cons; manual DI is simple to implement and works well for small projects whereas using an external container/framework makes sense in a large project with many team members because it provides a consistent manner of doing things across the project.
There is no learning curve when doing manual DI and with the current IDE’s it is easy to find who calls the method to inject the implementation. Even developers who are not very familiar with DI can contribute to the project. Unlike the manual approach, when using a container there is a learning curve. However, once you understand the framework it helps you manage your projects with ease. The wiring, scopes and rules of instantiation are all declarative. This makes it easy to understand how the application is wired together and therefore easier to change. Moreover while testing, fake implementations are sometimes needed in place of key components and an automated framework does this for you. Also, there is no need to write factory classes by hand any more as the framework takes care of creating and returning the correct objects for you.
On the flip side, some frameworks which maintain verbose configuration files mandate that the developer understands code in addition to the configurations beforehand, which can become an added overhead.
Supported Injection Type: I have mentioned in detail about dependency injection types previously. All the containers currently support many types of injections (setter, constructor, interface, field etc). However, Spring prefers Setter Injection though Guice and Pico prefer Constructor Injection.
Annotations: For some, use of annotations can be really compelling as it clearly delineates what dependency is being injected in the code and you do not have to examine the configuration file. But for others it may seem to spatter the code with unnecessary information and couple it with the frameworks jars, which might seem to be exactly opposite of what is the point of Dependency Injection; creating a loosely coupled system.
Third party injection: When it comes to injecting third party components into your project Spring provides you direct support for this. In Guice however, there is a roundabout approach for this as in most cases you cannot inject annotations into third party components. So a custom provider needs to be written to wire up the component.
Type Safety: Guice and Pico are both Type Safe as everything is present in the code itself and is statically checked at compile time. Using JavaConfig in Spring is a type safe option although if you use external configuration files (XML), theoretically runtime errors can occur. Even then those errors are all caught early as the framework does check eagerly on loading.
Speed: To some it may be important but conclusive comparisons among frameworks is not yet available. However according to some; Guice seems to be more lightweight and faster that both Pico and Spring. Spring is much more that just a dependency injection container and as such will have a large code footprint.
External Configuration files: External configuration files seem to be a good way of keeping your code free from framework related stuff but if the project becomes really large with multiple configuration files it can become hard to understand what dependency configuration goes where. Spring supports external configuration through XML files but Guice and Pico does not.
Leverage existing IDE capabilities: Most of the frameworks leverage current IDE capabilities to support the user like easy refactoring. Pico and Guice have more support here as everything is inside the code but when using external configuration files which may not be always visible to the IDE it may be a problem.
All these frameworks have been around for sometime and each framework has its own strengths. You should choose one from the above criteria depending on your project needs. No matter which one you chose or even if you go on and make your own DI container, you will benefit immensely by keeping your code easily testable and manageable.
Update(May 10, 2010): Updated Supported Injection Type comment regarding Guice and Spring injection preference.