Google Guice简介

最近看graylog代码,发现使用了google的Guice,几个月前查看es代码也用到guice,还有不记得的好多github开源项目都使用了Google Guice,所以今天简单学习一下Google Guice概念。

Google Guice:

google guice是一个轻量级的依赖注入框架啊,

Guice基本概念:

  • Guice:                      整个框架的门面
  • Injector:                一个依赖的管理上下文,负载管理所有的Binder
  • Binder:                    一个接口和实现的绑定
  • Module:                    一组 Binder
  • Provider:                 bean 的提供者
  • KeyBinder               中对应一个 Provider
  • ScopeProvider        的作用域

Guice数据结构,根据Module 创建Injector

public final class Guice {
    private Guice() {
    }

    public static Injector createInjector(Module... modules) {
        return createInjector((Iterable)Arrays.asList(modules));
    }

    public static Injector createInjector(Iterable<? extends Module> modules) {
        return createInjector(Stage.DEVELOPMENT, modules);
    }

    public static Injector createInjector(Stage stage, Module... modules) {
        return createInjector(stage, (Iterable)Arrays.asList(modules));
    }

    public static Injector createInjector(Stage stage, Iterable<? extends Module> modules) {
        return (new InternalInjectorCreator()).stage(stage).addModules(modules).build();
    }
}

Injector: 获取binding, provider, T实例

public interface Injector {
    void injectMembers(Object var1);

    <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> var1);

    <T> MembersInjector<T> getMembersInjector(Class<T> var1);

    Map<Key<?>, Binding<?>> getBindings();

    Map<Key<?>, Binding<?>> getAllBindings();

    <T> Binding<T> getBinding(Key<T> var1);

    <T> Binding<T> getBinding(Class<T> var1);

    <T> Binding<T> getExistingBinding(Key<T> var1);

    <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> var1);

    <T> Provider<T> getProvider(Key<T> var1);

    <T> Provider<T> getProvider(Class<T> var1);

    <T> T getInstance(Key<T> var1);

    <T> T getInstance(Class<T> var1);

    Injector getParent();

    Injector createChildInjector(Iterable<? extends Module> var1);

    Injector createChildInjector(Module... var1);

    Map<Class<? extends Annotation>, Scope> getScopeBindings();

    Set<TypeConverterBinding> getTypeConverterBindings();
}

每个绑定 Binding<T> 的结构如下:

public interface Binding<T> extends Element {
    Key<T> getKey();

    Provider<T> getProvider();

同时它继承了 Element,里面包含了 Source:

public interface Element {
    Object getSource();

可以看出每个绑定 Binding<T>,包含一个键 Key<T> 和 一个提供者 Provider

对于每一个提供者 Provider,它提供所需类型的实例:

  • 你可以提供一个类,Guice 会帮你创建它的实例。
  • 你也可以给 Guice 一个你要绑定的类的实例。
  • 你还可以实现你自己的 Provider<T>,Guice 可以向其中注入依赖关系。

每个绑定还有一个可选的作用域。缺省情况下绑定没有作用域,Guice 为每一次注入创建一个新的对象。一个定制的作用域可以使你控制 Guice 是否创建新对象。例如,你可以使用 为每一个 HttpSession 创建一个实例。

injector.getInstance(XXX.class); 的过程:
先根据指定的类来 new Key()Key 包括类信息 XXX.class 和注解信息,XXX.classhashcode 和注解的 hashcode 决定了 KeyhashcodegetProvider 时是根据 Keyhashcode 来判断是否是同一个Key,然后取到 Provider,由 Provider 提供最终的示例。

Google Guice 示例:

添加 Maven 的依赖:

<dependency>
    <groupId>com.google.inject</groupId>
    <artifactId>guice</artifactId>
    <version>4.0</version>
</dependency>

我们首先定义 Communicator 接口,和它的一个实现类 DefaultCommunicatorImpl

public interface Communicator {
    boolean sendMessage(String message);
}
public class DefaultCommunicatorImpl implements Communicator {
    public boolean sendMessage(String message) {
        System.out.println("Sending Message + " + message);
        return true;
    }
}

随后我们通过 @Inject 注解来在 Communication 类中注入 Communicator 类的依赖:

import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

import java.util.logging.Logger;

public class Communication {
    @Inject
    private Communicator communicator;

    public Communication(Boolean keepRecords) {
        if (keepRecords) {
            System.out.println("Message logging enabled");
        }
    }

    public boolean sendMessage(String message) {
        communicator.sendMessage(message);
        return true;
    }

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new BasicModule());

        Communication comms = injector.getInstance(Communication.class);

        comms.sendMessage("hello world");
    }
}

main() 中,可以看到我们通过 Injector 得到了一个 Communication 实例,随后调用了 sendMessage() 方法。

那么 BasicModule 类又是怎么样的呢?

The Module is the basic unit of definition of bindings. 定义依赖绑定的基本单元。

  • 它需要继承 AbstractModule
  • 它将 Communication 绑定了到一个实例 Instance,传入参数 true 到构造方法
  • 它将 Communicator 绑定了到一个具体的实现 DefaultCommunicatorImpl
import com.google.inject.AbstractModule;

public class BasicModule extends AbstractModule {

    @Override
    protected void configure() {
        // 表明:当需要 Communicator 这个变量时,我们注入 DefaultCommunicatorImpl 的实例作为依赖
        bind(Communicator.class).to(DefaultCommunicatorImpl.class);

        bind(Communication.class)
                .toInstance(new Communication(true));
    }
}

运行输出如下:

Message logging enabled
Sending Message + hello world

我们也可通过 @Provides 注解来在 BasicModule 中定义依赖:

public class BasicModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Communication.class)
                .toInstance(new Communication(true));
    }

    @Provides
    @Singleton
    public Communicator getCommunicator() {
        return new DefaultCommunicatorImpl();
    }
}

其中 @Singleton 注解表明这个依赖的 Scope 是单例,它是延时加载的 lazily initiated。

如果我们对一个依赖进行了多次绑定,例如:

@Provides
@Singleton
public Communicator getCommunicator() {
    return new DefaultCommunicatorImpl();
}

@Provides
@Singleton
public Communicator getCommunicatorOneMoreTime() {
    return new DefaultCommunicatorImpl();
}

运行时会抛出如下的异常:

1) A binding to demo.guice.Communicator was already configured at demo.guice.BasicModule.getCommunicator().
  at demo.guice.BasicModule.getCommunicator(BasicModule.java:17)

1 error
    at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:466)
    at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:155)
    at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:107)
    at com.google.inject.Guice.createInjector(Guice.java:96)
    at com.google.inject.Guice.createInjector(Guice.java:73)
    at com.google.inject.Guice.createInjector(Guice.java:62)

假如我们现在有了 Communicator 接口的另外一种实现 AnotherCommunicatorImpl

public class AnotherCommunicatorImpl implements Communicator {
    public boolean sendMessage(String message) {
        System.out.println("Another Sending Message + " + message);
        return true;
    }
}

同时我们在 Communication 类中需要同时依赖于原有的 DefaultCommunicatorImpl 和新定义的 AnotherCommunicatorImpl,例如:

public class Communication {

    @Inject
    private Communicator communicator;

    @Inject
    private Communicator anotherCommunicator;

    public Communication(Boolean keepRecords) {
        if (keepRecords) {
            System.out.println("Message logging enabled");
        }
    }

    public boolean sendMessage(String message) {
        communicator.sendMessage(message);

        anotherCommunicator.sendMessage(message);

        return true;
    }

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new BasicModule());

        Communication comms = injector.getInstance(Communication.class);

        comms.sendMessage("hello world");
    }
}

那么我们在 BasicModule 应该怎么定义这种绑定呢?
如果我们尝试添加另外一个 @Provides 方法,返回 AnotherCommunicatorImpl,例如:

@Provides
@Singleton
public Communicator getCommunicator() {
    return new DefaultCommunicatorImpl();
}

@Provides
@Singleton
public Communicator getAnotherCommunicator() {
    return new AnotherCommunicatorImpl();
}

则会有如下的异常:

Exception in thread "main" com.google.inject.CreationException: Unable to create injector, see the following errors:

1) A binding to demo.guice.Communicator was already configured at demo.guice.BasicModule.getCommunicator().
  at demo.guice.BasicModule.getAnotherCommunicator(BasicModule.java:23)

这里我们需要通过 @Named 注解提供为属性赋值的功能。
首先在注入绑定的时候使用 @Named 注解:

@Inject
@Named("communicator")
private Communicator communicator;

@Inject
@Named("anotherCommunicator")
private Communicator anotherCommunicator;

随后在定义绑定的时候使用 @Named 注解:

@Provides
@Singleton
@Named("communicator")
public Communicator getCommunicator() {
    return new DefaultCommunicatorImpl();
}

@Provides
@Singleton
@Named("anotherCommunicator")
public Communicator getAnotherCommunicator() {
    return new AnotherCommunicatorImpl();
}

运行结果如下:

Message logging enabled
Sending Message + hello world

Another Sending Message + hello world

猜你喜欢

转载自blog.csdn.net/wjandy0211/article/details/105726116