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:
Module
interface
or extends AbstractModule
.
This class will define bindings, for example,
from interfaces to implementation classes.Injector
and use it to obtain objects,
for example,
objects from classes that implement a given interface.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.
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; } }
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 } }
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; } }
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.
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.