Friday, April 13, 2007

[Tech] Dependency Injection with Guice

Overview

Dependency Injection is a software pattern for writing high quality testable software. The Java world recently got a new framework named Guice that was developed by Google and that provides an interesting alternative for people who fear (XML) configuration files.

If you never came across this topic, Martin Fowlers excellent article "Inversion of Control and the Dependency Injection pattern" is highly recommended.

Refresher on Dependency Injection

It's common for classes in object oriented environments, that they can't provide the requested functionality on their own, but need to use external services (classes connected using delegation). The easiest way is to create the required service is using the new() operator when needed. This will work at first but as soon as you want to replace the service with another implementation you run into problems and have to modify the code in many places (and rebuild the application). With modern refactoring tools this still wouldn't cause you a lot of headaches but when it comes to testing this approach really starts to hurt. Unit testing your object without testing the service gets impossible so a more dynamic approach for accessing the service becomes necessary.

Moreover, modern application design often prefers late-binding and loose-coupling, meaning, that some implementation details can be decided very late in the process, in many cases at the customer (e.g., which driver is uses, how a specific driver or module is configured). These configuration steps should also be feasible without refactoring of the application as this would mean a different code-basis for every customer!

You basically have two choices:

1.Using a Service Locator that creates and returns the right service implementation depending on the context.
2. Someone else provides the right service; either during construction time or by using a factory pattern during runtime and calling setter-method(s).

Dependency Injection frameworks are particularly useful if you go for the second option. You first tell the framework which implementation to use for which interface. Whenever you then request an object of that interface you not only get the right implementation, but the requested objects dependencies, and their dependencies, and so on (recursively if needed), are also automatically resolved by the framework. It's considered best practice that the configuration of the framwork happens during the bootstrapping process and a single fully configured object is requested once from the framework. Most classes are not even aware of the injection framework (at least in the case of popular frameworks like Spring).

Dependency Injection with Guice

If you're used to Spring you will be surprised, that frameworks like Guice don't necessarily need large, hard, in some cases hard to maintain, external configuration files. In Guice all your configuration is done in code and uses the annotation features of Java 1.5.

Configurations are separated in Modules by either implementing the Module interface or by inheriting from the AbstractModule class. Within the configure() method you then bind interfaces to their implementations.

public class MyModule implements Module {
public void configure(Binder binder) {

binder.bind(Service.class)
.to(ServiceImpl.class)
.in(Scopes.SINGLETON);

}


The example above is taken from the Guice documentation and binds the interface "Service" to the implementation "ServiceImpl". It also sets the service scope to be Singleton. Scopes deserve an article on their own, but basically they request a specific life cycle behavior for the object.

public class MyObject {

private final Service service;

@Inject
public Client(Service service) {
this.service = service;
}
}
A class that needs a service would just add a parameter to its constructor (or define a method that takes the service as an argument) and annotate it with the @Inject annotation.
public class FooApplication {
public static void main(String[] args) {
Injector injector = Guice.createInjector(
new MyModule(),
);

MyObject starter = injector.getInstance(MyObject.class);

// do something useful
}
}


During application startup an Injector is created with one or more modules as configuration. It is then used to request our object. Under the hood it will 1. create an instance of the class (depending on the scope), 2. look at all methods that we declared with @Inject and 3. supply the required services (back to 1).

External Configuration vs. Code-based Injection

There are good reasons not to use Guice especially if you like configuration files. It's true that you would have to recompile at least part of your code if you change the configuration. This would become a problem if you deploy your application to many targets that need to be configured differently. On the other hand configuration in code provides huge advantages: refactoring becomes much easier, your configuration files have to stay current otherwise your build will fail, in general readability is higher, and your development environment will help you with auto completion to configure your application much more quickly. The Module concept of Guice also allows you a more hybrid way: depending on some simple eg. property file, you could pick the right module during bootstrapping of the application. Which way you choose strongly depends on the needs of your application.

Summary

We just scratched the suface of Guice but showed the ease of use of the framework. Although it doesn't have as many features as Spring, it should be considered for projects where you want to reduce XML configuration files and need a slim fast dependency injection framework.

5 comments:

Alexander Schatten said...

I see the point in doing DI on a code-basis, however I personally always found the Spring-configuration approach more powerful. Guice appears to be conceptionally very similar to Picocontainer and Nanocontainer from the Codehaus project.

My impression is rather this: these libraries are "core DI" libraries, whereas the Springframework goes beyond this (only speaking about the container part here). I see DI not only about wiring together object graphs (which is apparently the core functionality of libraries like Guice, Pico and Nano) but also in configuration management.

And here is Spring significantly superior, as far as I understand it: In Spring not only the "wiring" is done in the XML config, but also the initialisation with constant parameters. This can also happen in two stages: XML file for "wiring", refering to properties file for constant properties.

The argument for better tool/refactoring support is also not necessary valid from my point of view: Actually, the fact that Spring externalises the dependencies allows easier analysis of those. There are meanwhile plugins for e.g. Eclipse awailable to support for visual work with Spring configs like Spring IDE. I once wrote a simple XSLT file that visualised the dependencies in a project based on the beans.xml by providing an HTML view.

So I am personally rather sceptical to the code-based DI container implementations. From my understanding they reach not far enough in functionality.

Bob said...

Guice supports properties files.

Alexander Schatten said...

Actually Nano-Container does too; it extends Pico-Container with various "language" support inluding XML configuration (to a certain extent).

Would be interesting to discuss, where the concrete differences between the frameworks are. My feeling is (but I have actually only good experience with Spring) that Spring is the most elaborate one.

Benedikt Eckhard said...

In my opinion "pure" DI frameworks also have their legitimation, maybe because I don't see DI's primary role in configuration management. For me DI is an architectural skill that's amazingly useful in writing maintainable code.

For me dependency injection IS about wiring components together and not about managing all kinds of configuration. In this sense code based configuration makes perfect sense for me. It is very tolerant to refactoring, guarantees that the configuration stays current, and is in my opinion just nicer to read and understand. Of course there are tools that support you in maintaining your external configuration files, but these tools become one more application you need to maintain and keep up to date.

If you're building complex application that are deployed to multiple environments with different configuration needs, or i f you want to use DI also for all your configuration needs, then external configuration files are the way to go and the Spring based approach should be favoured.

Gerd Saurer said...

May be someone is interested in watching a video about Guice http://www.theserverside.com/news/thread.tss?thread_id=45174