Guice @Provides方法与提供者类

时间:2015-01-28 21:36:46

标签: java dependency-injection guice roboguice

我正在开展一个有很多注射的大型项目。我们目前正在使用一个为每个需要一个注入实现Provider的类,它们大多有一行get方法。

每次我需要一个新的提供者时,创建一个新类就开始变得烦人。在@Provides中使用提供程序类而不是Module方法有什么好处,反之亦然?

2 个答案:

答案 0 :(得分:18)

据我所知,它们与大多数简单案件完全相同。

/**
 * Class-style provider.
 * In module: bind(Foo.class).annotatedWith(Quux.class).toProvider(MyProvider.class);
 */
class MyProvider implements Provider<Foo> {
  @Inject Dep dep;  // All sorts of injection work, including constructor injection.

  @Override public Foo get() {
    return dep.provisionFoo("bar", "baz");
  }
}

/**
 * Method-style provider. configure() can be empty, but doesn't have to be.
 */
class MyModule extends AbstractModule {
  /** Name doesn't matter. Dep is injected automatically. */
  @Provides @Quux public Foo createFoo(Dep dep) {
    return dep.provisionFoo("bar", "baz");
  }

  @Override public void configure() { /* nothing needed in here */ }
}

在任何一种风格中,即使密钥绑定到类或实例,Guice也允许您注入FooProvider<Foo>。如果直接获取实例,Guice会自动调用get,如果不存在,则创建隐式Provider<Foo>。绑定注释在两种样式中都有效。

@Provides的主要优点是紧凑性,特别是与匿名内部Provider实现相比。但请注意,在某些情况下,您可能希望使用Provider类:

  • 您可以使用构造函数参数创建自己的长期存在的Provider实例,并将键绑定到这些实例而不是类文字。

    bind(Foo.class).toProvider(new FooProvisioner("bar", "baz"));
    
  • 如果您使用的是与JSR 330(javax.inject)兼容的框架,则可以轻松绑定到javax.inject.Provider类或实例。 com.google.inject.Provider扩展了该界面。

    bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class);
    
  • 您的提供商可能很复杂,无法考虑自己的类。根据您的测试结构,可能更容易以这种方式测试您的提供商。

  • 提供者可以扩展抽象类。使用@Provides方法执行此操作可能并不容易或直观。

  • 您可以直接将多个密钥绑定到同一个提供商。每个@Provides方法只产生一个绑定,但你可以将其他键绑定到(这里是@Quux Foo),让Guice再做一次查找。

  • 如果您希望(例如)在不使用Guice范围或绑定的情况下缓存或记忆实例,则提供程序很容易装饰或换行。

    bind(Foo.class).toProvider(new Cache(new FooProvisioner("bar", "baz")));
    

重要:虽然这对于Guice无法创建的课程来说是一个很好的策略,但请记住,Guice可以自动为您{{T}的任何T创建并注入Provider<T> 1}}以任何方式,包括类名,密钥或实例。除非您自己的实际逻辑涉及,否则无需创建显式提供程序。

答案 1 :(得分:0)

实例化类的方式也有所不同。 对于Eg:

public class GumProvider implements Provider<Gum> {

  public Gum get() {
    return new Gum();
  }
}
public class GumModule extends AbstractModule {

    protected void configure() {

        bind(Gum.class).toProvider(GumProvider.class);
        //bind(Gum.class).to(GumballMachine.class);
    }
}
public class GumballMachine {

    @Inject
    private Provider<Gum> gumProvider;

    Gum gum;


    public Gum dispense() {
        return gumProvider.get();
    }
}
public class App {

    public static void main(String[] args) {
      // TODO Auto-generated method stub
      Injector injector = Guice.createInjector(new GumModule());
      GumballMachine m = injector.getInstance(GumballMachine.class);
      System.out.println(m.dispense());
      System.out.println(m.dispense());


    }

}

这会创建一个每次调用的Gum实例。 而如果使用@Provides,则相同的Gum实例将被传递给注射器