-
Notifications
You must be signed in to change notification settings - Fork 1.7k
GettingStarted
How to start doing dependency injection with Guice.
Guice is a framework that makes it easier for your application to use the dependency injection (DI) pattern. This getting started guide will walk you through a simple example of how you can use Guice to incorporate dependency injection into your application.
Dependency injection is a design pattern wherein classes declare their dependencies as arguments instead of creating those dependencies directly. For example, a client that wishes to call a service should not have to know how to construct the service, rather, some external code is responsible for providing the service to the client.
Here's a simple example of code that does not use dependency injection:
class Foo {
private Database database; // We need a Database to do some work
Foo() {
// Ugh. How could I test this? What if I ever want to use a different
// database in another application?
this.database = new Database("/path/to/my/data");
}
}
The Foo
class above creates a fixed Database
object directly. This prevents
this class from being used with other Database
objects and does not allow the
real database to be swapped out for a testing database in tests. Instead of
writing untestable or inflexible code, you can use dependency injection pattern
to address all these issues.
Here's the same example, this time using dependency injection:
class Foo {
private Database database; // We need a Database to do some work
// The database comes from somewhere else. Where? That's not my job, that's
// the job of whoever constructs me: they can choose which database to use.
Foo(Database database) {
this.database = database;
}
}
The Foo
class above can be used with any Database
objects since Foo
has no
knowledge of how the Database
is created. For example, you can create a test
version of Database
implementation that uses an in-memory database in tests to
make the test hermetic and fast.
The Motivation page explains why applications should use the dependency injection pattern in more detail.
Java class constructors that are annotated with @Inject
can be called by Guice
through a process called
constructor injection, during which the
constructors' arguments will be created and provided by Guice.
Here is an example of a class that uses constructor injection:
class Greeter {
private final String message;
private final int count;
// Greeter declares that it needs a string message and an integer
// representing the number of time the message to be printed.
// The @Inject annotation marks this constructor as eligible to be used by
// Guice.
@Inject
Greeter(@Message String message, @Count int count) {
this.message = message;
this.count = count;
}
void sayHello() {
for (int i=0; i < count; i++) {
System.out.println(message);
}
}
}
In the example above, the Greeter
class has a constructor that is called when
application asks Guice to create an instance of Greeter
. Guice will create the
two arguments required, then invoke the constructor. The Greeter
class's
constructor arguments are its dependencies and applications use Module
to tell
Guice how to satisfy those dependencies.
Applications contain objects that declare dependencies on other objects, and
those dependencies form graphs. For example, the above Greeter
class has two
dependencies (declared in its constructor):
- A
String
object for the message to be printed - An
Integer
object for the number of times to print the message
Guice modules allow applications to specify how to satisfy those dependencies.
For example, the following DemoModule
configures all the necessary
dependencies for Greeter
class:
/**
* Guice module that provides bindings for message and count used in
* {@link Greeter}.
*/
import com.google.inject.Provides;
class DemoModule extends AbstractModule {
@Provides
@Count
static Integer provideCount() {
return 3;
}
@Provides
@Message
static String provideMessage() {
return "hello world";
}
}
DemoModule
uses the @Provides
methods to specify the
dependencies.
In a real application, the dependency graph for objects will be much more complicated and Guice makes creating complex object easy by creating all the transitive dependencies automatically.
To bootstrap your application, you'll need to create a Guice Injector
with
one or more modules in it. For example, a web server application might have a
main
method that looks like this:
public final class MyWebServer {
public void start() {
...
}
public static void main(String[] args) {
// Creates an injector that has all the necessary dependencies needed to
// build a functional server.
Injector injector = Guice.createInjector(
new RequestLoggingModule(),
new RequestHandlerModule(),
new AuthenticationModule(),
new DatabaseModule(),
...);
// Bootstrap the application by creating an instance of the server then
// start the server to handle incoming requests.
injector.getInstance(MyWebServer.class)
.start();
}
}
The injector internally holds the dependency graphs described in your application. When you request an instance of a given type, the injector figures out what objects to construct, resolves their dependencies, and wires everything together. To specify how dependencies are resolved, configure your injector with bindings.
The following is a simple Guice application with all the necessary pieces put together:
package guicedemo;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provides;
import java.lang.annotation.Retention;
import javax.inject.Inject;
import javax.inject.Qualifier;
public class GuiceDemo {
@Qualifier
@Retention(RUNTIME)
@interface Message {}
@Qualifier
@Retention(RUNTIME)
@interface Count {}
/**
* Guice module that provides bindings for message and count used in
* {@link Greeter}.
*/
static class DemoModule extends AbstractModule {
@Provides
@Count
static Integer provideCount() {
return 3;
}
@Provides
@Message
static String provideMessage() {
return "hello world";
}
}
static class Greeter {
private final String message;
private final int count;
// Greeter declares that it needs a string message and an integer
// representing the number of time the message to be printed.
// The @Inject annotation marks this constructor as eligible to be used by
// Guice.
@Inject
Greeter(@Message String message, @Count int count) {
this.message = message;
this.count = count;
}
void sayHello() {
for (int i=0; i < count; i++) {
System.out.println(message);
}
}
}
public static void main(String[] args) {
/*
* Guice.createInjector() takes one or more modules, and returns a new Injector
* instance. Most applications will call this method exactly once, in their
* main() method.
*/
Injector injector = Guice.createInjector(new DemoModule());
/*
* Now that we've got the injector, we can build objects.
*/
Greeter greeter = injector.getInstance(Greeter.class);
// Prints "hello world" 3 times to the console.
greeter.sayHello();
}
}
The GuiceDemo
application constructed a small dependency graph using Guice
that is capable of building instances of Greeter
class. Large applications
usually have many Module
s that can build complex objects.
Read more on how to conceptualize Guice with a simple mental model.
-
User's Guide
-
Integration
-
Extensions
-
Internals
-
Releases
-
Community