Guice: differences between Singleton.class and @Singleton

前端 未结 1 1126
执笔经年
执笔经年 2020-12-31 01:33

In Guice, what\'s the difference between:

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


        
相关标签:
1条回答
  • 2020-12-31 02:31

    They are nearly identical. The @Singleton syntax is useful for annotating @Provides methods, or annotating the class itself (though I prefer to keep my scoping annotations inside modules).

    The difference lies in which key is marked Singleton, which has less to do with @Singleton versus Singleton.class (or Scopes.SINGLETON, asEagerSingleton, @Singleton class annotations, or toInstance implicit singletons) and more to do with what the default syntax makes easy. For example:

    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(); }
    }
    

    Above we've bound interface A to class AImpl, and interface B to class BImpl, but the behavior is different:

    • Injecting A will retrieve the same AImpl instance every time.
    • Injecting AImpl will retrieve a different AImpl every time, all of which are different than A's instance.
    • Injecting B will retrieve the same BImpl instance every time.
    • Injecting BImpl will also retrieve that same BImpl instance that B injects.

    As you can see, each key is different, and Guice will allow multiple implementation instances if only the interface is bound with Singleton. If you only ever inject A and B interfaces, the behavior looks identical, but if you inject both interfaces and implementations from the same Injector, you may see differing behavior.

    Similar logic goes for @Provides methods:

    • Injecting C will always return the same CImpl instance.
    • Injecting CImpl will create a new CImpl every time, unless CImpl has no injectable public zero-arg constructor—then the injection will fail.
    • Injecting D will always return the same DImpl instance.
    • Injecting DImpl will return a new instance every time, and each will be different than the one returned by D.
    • Injecting E will return the same EImpl instance every time.
    • Injecting EImpl will also retrieve that same instance E injects.

    This provides some flexibility. Imagine a hypothetical Cache that keeps a certain number of most-recently-retrieved objects, where you want to have @User Cache and @Product Cache both injectable. If you bind(Cache.class).in(Singleton.class), you will have one Cache shared between the objects (and any bare Cache injections), whereas if you bind(Cache.class).annotatedWith(User.class).to(Cache.class).in(Singleton.class) then the annotated key is kept in singleton scope and each object type will have its own cache.

    0 讨论(0)
提交回复
热议问题