【问题标题】:Binding a guava supplier using guice使用 guice 绑定一个番石榴供应商
【发布时间】:2020-12-16 04:06:32
【问题描述】:

我想做这样的绑定,

bind(Supplier<TestClass>).toProvider(Provider<Supplier<TestClass>>).in(Singleton.class);

提供程序由外部函数返回,因此,在toProvider() 内部,我调用该函数并返回Provider&lt;Supplier&lt;TestClass&gt;&gt;

供应商来自 guava,这样做的原因是,有一个与 TestClass 关联的文件,我需要读取该文件并将这些值分配给 TestClass 的各个字段。

并且该文件在运行时更改,因此我需要一种方法来刷新存储在 TestClass 中的值。待办事项我使用的番石榴供应商。 Guava 供应商有一个 get 方法,当调用该 get 方法时,如果我使用 memoizeWithExpiration() 创建实例,那么它会检查 TTL 值,如果它通过,那么我可以指定一个 lambda 函数来读取文件并分配值。

所以我需要像这样注入Supplier&lt;TestClass&gt;

@Inject
Supplier<TestClass> someClassSupplier;

但是用 Guice 进行绑定让我感到困惑。

【问题讨论】:

  • 你真的应该更新到 Guice 4(Guice 5 即将推出):Guice 3 真的很老,在 4 中提供了许多与你类似的极端情况的有用功能,而 3 中没有。

标签: java dependency-injection guava guice guice-3


【解决方案1】:

您可以使用以下类型的代码来做您想做的事:

class ServiceModule extends AbstractModule {
  private TestClass readTestClassFromFile() {
    return new TestClass();
  }

  // Cache an instance for 5 seconds.
  private final Supplier<TestClass> testClassSupplier = Suppliers.memoizeWithExpiration(this::readTestClassFromFile, 5, SECONDS);

  @Provides TestClass provideTestClass() { // Don't declare as singleton
    return testClassSupplier.get();
  }
}

那么,在你的课堂上:

class Service {
  
  @Inject
  Provider<TestClass> testClassProvider; // Inject the provider, not the instance itself, or any supplier.
  
  void doSomething() throws Exception {
    TestClass a = testClassProvider.get();
    TestClass b = testClassProvider.get();

    Thread.sleep(6000); // Sleep for 6 seconds

    TestClass c = testClassProvider.get();

    System.out.println(a == b); // Prints true
    System.out.println(a == c); // Prints false
  }
}

您请求了一种通用的方法,所以在这里,检查bindSupplier 方法:

import static com.google.common.base.Suppliers.memoizeWithExpiration;

import com.google.inject.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

public class Main {

  public static void main(String[] args) throws Exception {
    Guice.createInjector(new ServiceModule())
        .getInstance(Service.class)
        .doSomething();
  }

  static class ServiceModule extends AbstractModule {
    Dependency createDependency() { return new Dependency(); }

    // For Java 8+
    private <T> void bindSupplier(Class<T> type, Supplier<? extends T> supplier) {
      // Definitely avoid .in(Singleton.class) because you want the scope to be defined by the Supplier.
      bind(type).toProvider(supplier::get);
    }

// For Java 7 and less
//    private <T> void bindSupplier(Class<T> type, final Supplier<? extends T> supplier) {
//      bind(type).toProvider(new Provider<T>() {
//          @Override public T get() { return supplier.get(); }
//        });
//    }

    @Override protected void configure() {
      bindSupplier(Dependency.class,
          memoizeWithExpiration(this::createDependency, 3, TimeUnit.SECONDS));
    }

  }

  static class Dependency {}

  static class Service {

    @Inject Provider<Dependency> dependencyProvider;

    void doSomething() throws InterruptedException {
      Dependency a = dependencyProvider.get();
      Dependency b = dependencyProvider.get();
      Thread.sleep(4000);
      Dependency c = dependencyProvider.get();
      System.out.printf("a == b ? %s%n", a == b); // true
      System.out.printf("a == c ? %s%n", a == c); // false
    }
  }
}

【讨论】:

  • 我们可以把这个通用化吗?我的意思是,如果我这样定义,Supplier 可以吗?
  • @LakithMuthugala 我让它尽可能通用。检查答案的新部分。如果这还不够,那么您实际上别无选择。
  • 谢谢。 @Olivier Grégoire
猜你喜欢
  • 2019-08-25
  • 1970-01-01
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-15
相关资源
最近更新 更多