Guice @Provides方法与提供者类

Eli*_*zer 9 java dependency-injection guice roboguice

我正在研究一个有很多注射的相当大的项目.我们目前正在使用一个实现Provider每个需要一个注入的类的类,它们大多有一个行get方法.

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

Jef*_*ica 19

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

/**
 * 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 */ }
}
Run Code Online (Sandbox Code Playgroud)

无论是哪种风格,吉斯让你注入FooProvider<Foo>,即使键被绑定到一个类或实例.get如果直接获取实例,Guice会自动调用,如果Provider<Foo>不存在,则创建隐式实例.绑定注释在两种样式中都有效.

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

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

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

    bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class);
    
    Run Code Online (Sandbox Code Playgroud)
  • 您的提供商可能足够复杂,可以考虑自己的类.根据您的测试结构,以这种方式测试您的提供商可能更容易.

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

  • 您可以直接将多个密钥绑定到同一个Provider.每个@Provides方法只生成一个绑定,但您可以将其他键绑定到(此处为@Quux Foo),并让Guice进行第二次查找.

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

    bind(Foo.class).toProvider(new Cache(new FooProvisioner("bar", "baz")));
    
    Run Code Online (Sandbox Code Playgroud)

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