25

在 Guice 中,有什么区别:

// Inside your AbstractModule subclass:
@Override
public void configure() {
    bind(Service.class).to(ServiceImpl.class).in(Singleton.class);
}

和:

@Override
public void configure() {
    bind(Service.class).to(ServiceImpl.class);
}

@Provides @Singleton
public ServiceImpl providesService() {
    return new ServiceImpl();
}

他们都一样吗?您什么时候会使用其中一种?提前致谢。

4

1 回答 1

48

它们几乎相同。该@Singleton语法对于注释@Provides方法或注释类本身很有用(尽管我更喜欢将范围注释保留在模块中)。

不同之处在于哪个键被标记为 Singleton,这与@Singletonvs Singleton.class(或Scopes.SINGLETON, asEagerSingleton@Singleton类注释或toInstance隐式单例)关系不大,而与默认语法使简单化的关系更多。例如:

public class MyModule extends AbstractModule {
  @Override public void configure() {
    bind(A.class).to(AImpl.class).in(Singleton.class);

    bind(B.class).to(BImpl.class);
    bind(BImpl.class).in(Singleton.class);
  }

  @Provides @Singleton C provideC() { return new CImpl(); }

  @Provides @Singleton D provideD(DImpl dImpl) { return dImpl; }

  @Provides E provideE(EImpl eImpl) { return eImpl; }
  @Provides @Singleton EImpl provideEImpl() { return new EImpl(); }
}

上面我们已经将 interface 绑定A到 class AImpl,并将 interface绑定B到 class BImpl,但是行为是不同的:

  • 注入每次A都会检索相同的实例。AImpl
  • 注入每次AImpl都会检索一个不同AImpl的,所有这些都不同于A's 实例。
  • 注入每次B都会检索相同的实例。BImpl
  • 注入BImpl还将检索注入的同一BImpl实例B

可以看到,每个key都不一样,Guice只要接口绑定Singleton,就会允许多个实现实例。如果您只注入AB接口,则行为看起来相同,但如果您从同一个 Injector 注入接口和实现,您可能会看到不同的行为。

类似的逻辑也适用于@Provides方法:

  • 注入C将始终返回相同的CImpl实例。
  • 注入每次CImpl都会创建一个新的,除非没有可注入的公共零参数构造函数,否则注入将失败。CImplCImpl
  • 注入D将始终返回相同的DImpl实例。
  • InjectingDImpl每次都会返回一个新实例,并且每个实例都与D.
  • 注入每次E都会返回相同的实例。EImpl
  • 注入EImpl还将检索相同的实例E注入。

这提供了一些灵活性。想象一个假设Cache,它保留了一定数量的最近检索到的对象,这些对象是您想要拥有的@User Cache并且@Product Cache都是可注入的。如果你bind(Cache.class).in(Singleton.class)是,你将在对象之间共享一个缓存(以及任何裸Cache注入),而如果你是,bind(Cache.class).annotatedWith(User.class).to(Cache.class).in(Singleton.class)那么带注释的键将保留在单例范围内,并且每种对象类型都将拥有自己的缓存。

于 2013-02-09T02:36:54.827 回答