My favorites | Sign in
Google
                
Search
for
Updated Aug 06, 2009 by ffaber
GettingStarted  
How to start doing dependency injection with Guice.

Getting Started

With dependency injection, objects accept dependencies in their constructors. To construct an object, you first build it's dependencies. But to build each dependency, you need its dependencies, and so on. So when you build an object, you really need to build an object graph.

Building object graphs by hand is labour intensive, error prone, and makes testing difficult. Instead, Guice can build the object graph for you. But first, Guice needs to be configured to build the graph exactly as you want it.

To illustrate, we'll start the RealBillingService class that accepts its dependent interfaces CreditCardProcessor and TransactionLog in its constructor. To make it explicit that the RealBillingService constructor is invoked by Guice, we add the @Inject annotation:

class RealBillingService implements BillingService {
  private final CreditCardProcessor processor;
  private final TransactionLog transactionLog;

  @Inject
  RealBillingService(CreditCardProcessor processor, 
      TransactionLog transactionLog) {
    this.processor = processor;
    this.transactionLog = transactionLog;
  }

  @Override
  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    ...
  }
}

We want to build a RealBillingService using PaypalCreditCardProcessor and DatabaseTransactionLog. Guice uses bindings to map types to their implementations. A module is a collection of bindings specified using fluent, English-like method calls:

public class BillingModule extends AbstractModule {
  @Override 
  protected void configure() {

     /*
      * This tells Guice that whenever it sees a dependency on a TransactionLog,
      * it should satisfy the dependency using a DatabaseTransactionLog.
      */
    bind(TransactionLog.class).to(DatabaseTransactionLog.class);

     /*
      * Similarly, this binding tells Guice that when CreditCardProcessor is used in
      * a dependency, that should be satisfied with a PaypalCreditCardProcessor.
      */
    bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
  }
}

The modules are the building blocks of an injector, which is Guice's object-graph builder. First we create the injector, and then we can use that to build the RealBillingService:

 public static void main(String[] args) {
    /*
     * Guice.createInjector() takes your Modules, and returns a new Injector
     * instance. Most applications will call this method exactly once, in their
     * main() method.
     */
    Injector injector = Guice.createInjector(new BillingModule());

    /*
     * Now that we've got the injector, we can build objects.
     */
    RealBillingService billingService = injector.getInstance(RealBillingService.class);
    ...
  }

By building the billingService, we've constructed a small object graph using Guice. The graph contains the billing service and its dependent credit card processor and transaction log.


Comment by georg.oettl, Apr 22, 2009

I remember that a short time ago the call "injector.getInstance(RealBillingService?.class);" was regarded as an evil thing to do. `the advice was to use a provider instead. Isn't this valid any more?

Comment by limpbizkit, Jul 30, 2009

Calling Injector.getInstance() is a perfectly reasonable thing to do when you're bootstrapping your application. What's discouraged is injecting the injector everywhere, because it degrades to the service locator pattern.

Comment by alexnospam123, Aug 17, 2009

Where are the declarations for TransactionLog? and the other classes? I just don't get it. All of this code would just throw class not found exception. Please document this better.

Comment by lugieb...@gmail.com, Sep 06, 2009

It would help out a lot if you mentioned in the documentation somewhere that to get the injector all one needs to do is

@Inject
Injector injector;

It took me the better part of the last hour to figure that out.


Sign in to add a comment