Guice @Provides方法与提供者类

我正在研究一个有大量注射的大型项目。 我们目前正在使用一个为每个需要一个注入实现Provider的类,它们大多数都有一个get方法。

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

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

 /** * Class-style provider. * In module: bind(Foo.class).annotatedWith(Quux.class).toProvider(MyProvider.class); */ class MyProvider implements Provider { @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 。 如果直接获取实例,Guice会自动调用get如果不存在,则创建隐式Provider 。 绑定注释在两种样式中都有效。

@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方法执行此操作可能并不容易或直观。

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

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

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

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

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

 public class GumProvider implements Provider { 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 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实例将被传递给两个注射器