Guice

Contents

Introduction
Implementing Services
Defining Bindings
Obtaining Injected Instances
Instance Scope
Best Practices

Introduction

Guice is a dependency injection container for Java 5 and later. It is similar in purpose to Spring Inversion of Control (IOC). In Guice, injections points are typically defined using annotations instead of XML, as is common in Spring IOC.

Injection creates and initializes objects. Initialization can be performed by setting fields, invoking constructors and invoking methods. The values used for fields, constructor parameters and method parameters are specified in bindings, which are specified in modules. Typically when methods are used for initialization, their names begin with "set", but they can have any name.

Most of the Guice interfaces and classes you'll use in your code are in the com.google.inject package. I wonder why that wasn't named com.google.guice.

The basic steps to use Guice are:

  1. Create a class that implements the Module interface or extends AbstractModule. This class will define bindings, for example, from interfaces to implementation classes.
  2. Annotate fields, constructor parameters and method parameters that should be injected.
  3. Create an Injector and use it to obtain objects, for example, objects from classes that implement a given interface.

Implementing Services top

When using dependency injection, it is typical to code to interfaces. Many classes that implement the same interface can be created. For example, one class can be the "real" implementation and another can be a "mock" implementation that is used for testing. Classes that depend on an implementation of an interface can have a specific implementation be injected in one of three ways.

  1. setting a field of the interface type
  2. invoking a constuctor with a parameter of the interface type
  3. invoking a method with a parameter of the interface type

Here's an example of an interface and a class that implements it. Note that neither of these contains Guice-specific code.

package com.ociweb.guice; public interface Service { int countSomething(); }
package com.ociweb.guice; import com.ociweb.guice.Service; public class ServiceImpl implements Service { public int countSomething() { return 5; } }

Defining Bindings top

Here's an example of defining a binding from an interface to a class that implements it in a module. A module can be implemented as a class that implements the Module interface or extends the AbstractModule class. The latter is a little easier.

Method calls on a Binder object are intended to be chained together and resemble a domain-specific language (DSL). These methods include bind, to, in, toInstance, annotatedWith, toProvider and asEagerSingleton.

package com.ociweb.guice; import com.google.inject.AbstractModule; public class MyModule extends AbstractModule { @Override protected void configure() { bind(Service.class).to(ServiceImpl.class); // could define additional bindings here } }

Obtaining Injected Instances top

Here's an example of a class whose instances are injected by Guice. It also demonstrates obtaining injected instances.

package com.ociweb.guice; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; public class Client { @Inject // field injection private Service service; public static void main(String[] args) { // Note that createInjector can be passed any number of Module objects. Injector injector = Guice.createInjector(new MyModule()); // Use this approach for field and method injection. // When both a field and a method that takes that same type // are annotated with @Inject, the method is invoked. // The method doesn't have to be named set{type-name}. //Client client = new Client(); //injector.injectMembers(client); // Use this approach for constructor injection. Client client = injector.getInstance(Client.class); client.doIt(); } // This constructor is used when field or method injection is used. public Client() { } // This constructor is used when constructor injection is used. @Inject // constructor injection public Client(Service service) { this.service = service; } public void doIt() { System.out.println(service.countSomething()); } @Inject // method injection public void setService(Service service) { this.service = service; } }

Instance Scope top

By default, Guice creates a new instance for each injection. There are three ways to make it use the same instance for all injections of the same type. The first way is to use the in method when defining the binding. For example, our previous binding could be written like this.

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

The second way is to annotate the implementation class with @Singleton. This approach should probably be avoided in order to keep implementation classes free of Guice-specific code, in this case the annotation.

With the previous two approaches, the singleton instance isn't created until it is needed. The third way creates the singleton object when Guice is initialized. To do this, invoke asEagerSingleton() on the binding instead of the in method.

Best Practices top

  1. Only ask the Injector for one object, referred to as the "root object". The class of this object should use injection to obtain references to other objects on which it depends. The classes of those objects should do the same.

Copyright © 2008 Object Computing, Inc. All rights reserved.