Google Guice

Language: Java

Dependency Injection

Guice was created by Google to simplify dependency management in Java applications. Instead of manually instantiating objects and passing dependencies, Guice allows developers to define how objects are wired together using modules and annotations like @Inject. It supports scopes, providers, and AOP features, making it suitable for both small and enterprise applications.

Google Guice is a lightweight dependency injection framework for Java. It allows you to manage object creation and dependencies declaratively using annotations, reducing boilerplate and promoting loose coupling.

Installation

maven: Add dependency in pom.xml: <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>5.1.0</version> </dependency>
gradle: Add dependency in build.gradle: implementation 'com.google.inject:guice:5.1.0'

Usage

Guice provides a declarative way to bind interfaces to implementations and inject dependencies. It supports constructor, method, and field injection, scopes (singleton, request, etc.), providers, and AOP interceptors.

Basic dependency injection

import com.google.inject.*;

interface Service {
    void execute();
}

class ServiceImpl implements Service {
    public void execute() { System.out.println("Service executed"); }
}

class Client {
    private final Service service;
    @Inject
    Client(Service service) { this.service = service; }
    void doWork() { service.execute(); }
}

public class Main {
    public static void main(String[] args) {
        Injector injector = Guice.createInjector(binder -> binder.bind(Service.class).to(ServiceImpl.class));
        Client client = injector.getInstance(Client.class);
        client.doWork();
    }
}

Binds the Service interface to ServiceImpl and injects it into Client automatically.

Field injection

class Client {
    @Inject private Service service;
    void doWork() { service.execute(); }
}

Demonstrates injecting dependencies directly into fields.

Using Providers

class Client {
    private final Provider<Service> serviceProvider;
    @Inject
    Client(Provider<Service> serviceProvider) { this.serviceProvider = serviceProvider; }
    void doWork() { serviceProvider.get().execute(); }
}

Uses Provider to lazily fetch instances of a dependency when needed.

Singleton scope

binder.bind(Service.class).to(ServiceImpl.class).in(Singleton.class);

Ensures a single instance of ServiceImpl is shared across the application.

Custom module

class AppModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Service.class).to(ServiceImpl.class);
    }
}

Injector injector = Guice.createInjector(new AppModule());

Organizes bindings in a module for cleaner configuration.

Method injection

class Client {
    private Service service;
    @Inject void setService(Service service) { this.service = service; }
}

Injects dependencies using a setter method.

Error Handling

ConfigurationException: Occurs when bindings are missing or ambiguous. Ensure all required bindings are properly defined.
ProvisionException: Occurs when Guice fails to create an instance. Check for constructor exceptions or circular dependencies.

Best Practices

Prefer constructor injection over field or method injection for better testability.

Use Modules to centralize and manage bindings cleanly.

Leverage Singleton scope for stateless or shared services to save resources.

Use Providers for lazy or conditional dependency creation.

Combine Guice with AOP for cross-cutting concerns like logging and transactions.