PART I: Dependency Injection with Guice

Introduction

Guice(pronounced “juice”) is an ultra-lightweight, next-generation dependency injection container for Java 5 and later.In this article we’ll look at Guice in Action and Plain Old Factory for dependency injection. We will decide what and when to use dependency injection in our applications(desktop or web).

Why do you need Guice ?

Guice enables and provides the best of all worlds:

  • Easy unit testing
  • Maximal flexibility and maintainability
  • Minimal repetition.

Can’t this be done without Guice?

Yes you can with factory design pattern, but as the your application thens to grow Guice will be of great beneficial to your application.

Factory Patten

Before the term “Dependency Injection” was discovered, developers make use of factory design pattern to achieve the same effect in some aspects.In this example, a client depends on a UserAuthentication service interface for authenticating a user either by via JDBC (Database Server) or LDAP (LDAP Server).We’ll call it UserAuthentication.

We have two implementations of the service with JDBC as the default implementation of this service which the client should not depend directly on. If we decide to use a different service implementation in the future, we don’t want to go around and change all of our clients.

Implementations of UserAuthentication service :

  1. JDBC Implementation
  2. LDAP Implementation


Next, we will need to implement the factory class for our clients to use in getting an implementation of the service as well as a means of testing in a mock service.

Logic of UserAuthentication factory :

Pass the name of implementation to the factory service and the factory returns an instance of that implementation.By default, a JDBC implementation will be handed to the client if name of implementation cannot be found or is null.


The client uses the factory directly to access the service if it needs one. Additionally you can add extra logic so that service implementations can be registered to the factory. The factory then have knowledge of all different implementations (Registry, you call it) and can access an implementation from the registry.

A simple client for our UserAuthentication Service


What is happening?

Get an instance of factory and use factory to get an implementation based on the name. Use the implementation to test a dummy user by creating an instance of user and calling the login method of the service interface via which you pass the dummy user.

Running the Factory Client


Dependency injection by Hand

From Guice 1.0 Guide, I quote:

“The dependency injection pattern aims in part to make unit testing easier. We don’t necessarily need a specialized framework to practice dependency injection. You can get roughly 80% of the benefit writing code by hand.”

While the client asked the factory for a service in our previous example, with dependency injection, the client expects to have its dependency passed in. Don’t call me, I’ll be there when you need me.

Dependecy injection by hand will require us implementing a factory for the client so that each implementation of the service will be returned by the client factory.

Summary on Plain Old Factories and Dependency Injection by Hand

You will notice that both (plain old factories and injection by hand) require barely the same amount of code to accomplish.

Dependency injection by Guice

Writing factories and dependency injection logic by hand for every service and client can become tedious. Some other dependency injection frameworks even require you to explicitly map services to the places where you want them injected.

From Guice 1.0 Guide, I quote:

“Guice aims to eliminate all of this boilerplate without sacrificing maintainability.”

  1. In using Guice, you implement modules, com.google.inject.Module.I prefer AbstractModule class.
  2. Guice passes a binder to your module, and your module uses the binder to map interfaces to implementations.
  3. Guice allows you to scope services (Singleton:one instance or Prototype: an instance for each injection by default).

As a proof of concept, we will create a module called SimpleAuthenticationModule to bind UserAuthentication to JdbcUserAuthentication.

A module tells Guice what you want to be injected. Guice can inject to fields, contructors and methods.

How is the service injected to the client?

By annotating your fields, methods and constructors with @Inject.


public class Client {

@Inject

public void Client(Service service) { this.service=service;}

}

Use of @ImplementedBy annotation

Instead of implementing the AbstractModule, you can annotate the service with @ImplementedBy. This annotation takes the implementation class as its parameter. It eliminates even more boilerplate code.

Use of @Singleton annotation

Instead of binding a scope to your implementation as done in the SimpleAuthenticationModule, you can annotate your implementation with this annotation to single instance of your service.

Architectural Overview of Guice

There are two distinct stages in the architecture of Guice as enumerated in Guice 1.0 Guide. They are startup and runtime. Injection Points are created by the Injector after supplying it with modules and injection class.Guice can look at the classes you tell it about during this startup stage and any classes those classes know about, and tell you whether or not you’re missing any dependencies.

Guice Runtime model:
see Guice 1.0 User Guide for more details about the runtime stages.


Source: Guice 1.0 User Guide

Annotation Binding

For the UserAuthentication service, there are two implementation of it namely JdbcUserAuthentication and LdapUserAuthentication. How do we differentiate between the two implementations? Guice has an answer to that and this is what the annotation binding is to solve.

For this example, we will bind the annotation @LdapAuthentication to the service LdapUserAuthentication implementation and @JdbcAuthentication annotation to JdbcUserAuthentication implementation. Refer to Guice 1.0 Guide on how to create Binding Annotations.


Guice provides production-worthy implementation called @Named but we will implement our own as proof of concept.

Bootstrapping your application

The idea of bootstrapping is fundamental to dependency injection. Always explicitly asking the Injector for dependencies would be using Guice as a service locator, not a dependency injection framework.

Implementation of UserAuthentication using Guice

  1. Implement the AbstractModule and configure all your services for injection.


  2. Bootstrap your application and provide an access to Injector class.


  3. Use Injector object from the bootstrap stage and call injectMembers method for dependency injection.


Summary

We implemented factory pattern, dependency injection by hand and dependency injection by Guice ,and truly Guice gives you easy unit testing, minimal repetition and maximal flexibility and code maintainability.

In Part II, we will look at Dependency Injection with Guice in Spring.

Source code for this article can be downloaded at http://groups.google.com/group/jaccra/web/GuiceExample.zip. To run the application you will need:

  • IDE (Netbeans/Eclipse or just Ant)
  • Guice Library

Further Reading

http://code.google.com/p/google-guice/


~ by frankappiahnsiah on June 1, 2009.

Leave a Reply