guice中非单例的懒加载

Lazy load of non-singleton in guice

我在我的项目中使用 Guice 作为 DI,我想在我的 class 中对非单例对象进行延迟初始化。 我试图使用 Provider,但每次我调用 get() 方法时它都会返回新实例。

public class MyClass {
  @Inject
  private Provider<Service> serviceProvider; //Service is NOT Singleton

  public void meth1() {
    Service s1 = serviceProvider.get();       
  }

  public void meth2() {
    Service s2 = serviceProvider.get();
  }
  //I want  s1 and s2 to be the same object
}

Guice 可以做到吗,或者是否有任何其他做法可以做到这一点?

如果你需要 s1s2 来引用同一个实例,那么你只需要一个 Service 的实例来引用 MyClass 的实例,并且简单地解析为 实例字段 :

public class MyClass {

  @Inject
  private Provider<Service> serviceProvider;

  private Service service;

  public void meth1() {
    if (this.service == null) this.service = this.serviceProvider.get();
    // use service 
  }

  public void meth2() {
    if (this.service == null) this.service = this.serviceProvider.get();
    // use service 
  }
}

正如 Tavian 在评论中提到的那样,最好的解决方案是 Suppliers.memoize(serviceProvider::get),或一些等效的解决方案。 Suppliers (and Supplier) are in the Google utility library Guava, and since Java 8, Guava's Supplier extends the Java 8 functional interface Supplier,尽管 Java 8 不提供与 Suppliers 等效的内置功能。 serviceProvider::get 的规范对于使 Provider 在没有显式适配器的情况下充当 Supplier 是必要的,即使它们都指定了一个方法,即零参数 T get().

与 Google 的其他 DI 框架不同,Dagger, Supplier doesn't have a Lazy class to provide the local memoization you're looking for. Though you could do the kind of "check then set" behavior that tmarwen offers in , that strategy (as mentioned in their comment) is not thread-safe, while Suppliers.memoize 是明确的线程安全的。

虽然 Guava 提供了很多有用的功能,但您可能不想为单个方法添加一个全新的库。如果你确实需要没有完整库的线程安全,你可以看看 the Apache-licensed implementation here.