【问题标题】:Guice @Provides Methods vs Provider ClassesGuice @Provides 方法与提供者类
【发布时间】:2015-03-27 23:31:46
【问题描述】:

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

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

【问题讨论】:

    标签: java dependency-injection guice roboguice


    【解决方案1】:

    类的实例化方式也有所不同。 例如:

    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 Per Invocation 实例。 而如果使用@Provides,相同的 Gum 实例将被传递给两个注入器

    【讨论】:

      【解决方案2】:

      据我所知,它们对于大多数简单的情况都是完全等价的。

      /**
       * 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&lt;Foo&gt;,即使键绑定到类或实例。如果直接获取实例,Guice 会自动调用get,如果不存在,则创建隐式Provider&lt;Foo&gt;。绑定注解在这两种样式中都有效。

      @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);
        
      • 您的 Provider 可能足够复杂,可以考虑到它自己的类中。根据您构建测试的方式,以这种方式测试您的 Provider 可能会更容易。

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-26
        • 1970-01-01
        • 2018-08-04
        相关资源
        最近更新 更多