Java Guice @Provides 方法与提供者类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28202882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 05:46:48  来源:igfitidea点击:

Guice @Provides Methods vs Provider Classes

javadependency-injectionguiceroboguice

提问by Eliezer

I'm working on a fairly large project that has a lot of injections. We're currently using a class that implements Providerfor each injection that needs one, and they mostly have one line getmethods.

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

It's starting to get annoying to create a new class every time I need a new provider. Is there any benefit to using provider classes over @Providesmethods in my Moduleor vice-a-versa?

每次我需要一个新的提供者时,创建一个新类开始变得很烦人。@Provides在我的方法上使用提供程序类是否有任何好处,Module反之亦然?

采纳答案by Jeff Bowman

As far as I know, they're exactly equivalent for most simple cases.

据我所知,对于大多数简单的情况,它们完全相同。

/**
 * 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 */ }
}

In either style, Guice lets you inject Fooand Provider<Foo>, even if the key is bound to a class or instance. Guice automatically calls getif getting an instance directly and creates an implicit Provider<Foo>if one doesn't exist. Binding annotations work in both styles.

无论哪种风格,Guice 都允许您注入Fooand Provider<Foo>,即使键绑定到类或实例。get如果直接获取实例,Guice 会自动调用,如果Provider<Foo>不存在则创建隐式。绑定注释在两种风格中都有效。

The main advantage of @Provides is compactness, especially in comparison to anonymous inner Provider implementations. Note, however, that there might be a few cases where you'd want to favor Provider classes:

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

  • You can create your own long-lived Provider instances, possibly with constructor parameters, and bind keys to those instances instead of to class literals.

    bind(Foo.class).toProvider(new FooProvisioner("bar", "baz"));
    
  • If you're using a framework compatible with JSR 330 (javax.inject), you can easily bind to javax.inject.Provider classes or instances. com.google.inject.Provider extends that interface.

    bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class);
    
  • Your Provider may be complex enough to factor into its own class. Depending on how you've structured your tests, it may be easier to test your Provider this way.

  • Providers can extend abstract classes. It may not be easy or intuitive to do this with @Provides methods.

  • You can bind several keys to the same Provider directly. Each @Provides method produces exactly one binding, though you could bind other keys to the key(@Quux Foo here) and let Guice do a second lookup.

  • Providers are easy to decorate or wrap, if you wanted to (for instance) cache or memoize instances without using Guice scopes or bindings.

    bind(Foo.class).toProvider(new Cache(new FooProvisioner("bar", "baz")));
    
  • 您可以创建自己的长期 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);
    
  • 您的 Provider 可能很复杂,可以考虑到它自己的类中。根据您构建测试的方式,以这种方式测试您的 Provider 可能更容易。

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

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

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

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


IMPORTANT: Though this is a good strategy for classes that Guice can't create, bear in mind that Guice can automatically create and inject a Provider<T>for any T that you bindin any way, including to a class name, key, or instance. No need to create an explicit provider unless there's actual logic of your own involved.

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

回答by Jamie J

There is also a difference in how classes are instantiated. For 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());


    }

}

This would create an Instance of Gum Per Invocation. Whereas if @Provides were used the same Instance of Gum would be passed to both the Injectors

这将创建一个 Gum Per Invocation 实例。而如果使用@Provides,则相同的 Gum 实例将被传递给两个注入器