Guice 是 Google 开源的一个用于 Java 的轻量级依赖注入框架(elasticsearch 在最初使用的依赖注入框架也是 Guice)。

抽象地回顾 Guice 的基本要点,目的是更好的使用 Guice 完成项目中对象的装配。

将 Guice 视作一个 Map

在装配一个实例时需要一些其他的实例,这些其他的实例便是依赖,为了获取对应的实例,我们需要一个实例的标识(Identifier),这个标识便是 Guice Key ,key 指向的实例(依赖)便是 value,考虑到实例可能需要动态的创建,那么不将实例直接作为 value,而是将可以提供实例的一个工厂作为 value,这个工厂便是 Provider

Guice Key

对于最简单的情况,一个实例的类型即可作为这个实例的 Guice Key ,例如 Key.get(String.class) 即可创建一个 Guice Key 对象(在实际使用中我们并不需要手动的创建 Guice Key ,只需要在需要注入依赖的构造方法上声明即可, Guice Key 的创建将由 Guice 自动完成)。

而 Guice 这个 Map 中存在类型相同的两个实例作为 Value,他们的类型不能直接的区分出这两个实例,那么我们在构造方法上以类型声明依赖的时候便无法决定出具体需要哪一个实例,于是出现了 binding annotation ,在构造方法的参数上通过注解和类型组合成一个唯一的 Key,例如需要两个相同类型不同实例的构造方法可以这样声明:

final class MultilingualGreeter {
	private String englishGreeting;
    private String spanishGreeting;
    
    @Inject
    MultilingualGreeter(@English String englishGreeting, @Spanish String spanishGreeting) {
    	this.englishGreeting = englishGreeting;
        this.spanishGreeting = spanishGreeting;
    }

在这种情况下实际创建 Guice Key 的调用为 Key.get(String.class, English.class)

总之,Guice Key 就是一个注解和类型组合出的实例的唯一标识。

Provider

Provider 是一个具有返回实例的方法的接口,具体的接口声明如下:

interface Provider<T> {
	T get();
}

我们在使用 Guice 的时候并不会手动的定义 Provider 而是 Guice 通过扫描 Module 子类的方法,为这些方法自动的创建 Provider ,例如:

class DemoModule extends AbstractModule {
	@Provides
    @Count
    static Integer provideCount() {
    	return 3;
    }
}

使用 Guice

使用 Guice 分为两部分,配置和注入(类似于 spring )。

Guice 配置

配置 Guice 也就是将实例的定义交给 Guice(之后 Guice 便负责创建实例和为实例注入依赖,将实例作为依赖注入给其他实例)。

Guice 的配置在 Module 类中文完成,有两种配置方式,一种便是上文中提到的声明注解 @Provides 方法,另一种是使用 Guice 的领域语言(DSL),简单的说就是使用方法的调用进行配置。一些方法和上面的 Map 模型的对应如下:

Guice DSL syntax Mental model
bind(key).toInstance(value) map.put(key, () -> value)
(instance binding)
bind(key).toProvider(provider) map.put(key, provider)
(provider binding)
bind(key).to(anotherKey) map.put(key, map.get(anotherKey))
(linked binding)
@Provides Foo provideFoo() {...} map.put(Key.get(Foo.class), module::provideFoo)
(provider method binding)

Guice 注入

Guice 注入便是从 Guice 的 Map 中获取一个 value 提供给一个构造方法。你不需要从 Guice 的 Map 中手动获取一个实例,只需要在构造方法上声明即可。

为了声明一个沟总方法需要 Guice 的注入,可以:

  1. 在构造方法上使用注解 @Inject
  2. 作为配置 Guice 的 Module 的类中,被注解为 @Provides 的方法的注入也会通过 Guice 进行。

下篇:

Guice Review 实例的域
Coding, rescue my life.