Guice: differences between Singleton.class and @Singleton

In Guice, what's the difference between:

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

      

and

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

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

      

Are they both the same? When will you use one against the other? Thanks in advance.

+3


source to share


1 answer


They are almost identical. The syntax @Singleton

is useful for annotating methods @Provides

or annotating the class itself (although I prefer to keep my scoped annotations inside modules).

The difference is that the key is marked singleton, which is less linked to @Singleton

anti Singleton.class

(or Scopes.SINGLETON

, asEagerSingleton

, @Singleton

annotation class or toInstance

implicit singletons) and more to do with the fact that simplifies the default syntax. 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 have bound an interface A

to a class AImpl

and an interface B

to a class BImpl

, but the behavior is different:

  • The injection A

    will fetch the same instance AImpl

    every time.
  • Injecting AImpl

    will get different each time AImpl

    , all of which are different from the instance A

    .
  • The injection B

    will fetch the same instance BImpl

    every time.
  • The injection BImpl

    will also retrieve the same BImpl

    instance that it B

    inserts.


As you can see, each key is different and Guice allows multiple instances of the implementation as long as the interface is associated with a Singleton. If you only inject interfaces A

and B

, the behavior looks the same, but if you inject both interfaces and implementations from the same Injector, you can see different behavior.

Similar logic for methods @Provides

:

  • Input C

    always returns the same instance CImpl

    .
  • Injection CImpl

    will create a new CImpl

    one every time, unless CImpl

    it has an injectable public constructor with a null-arg argument, then the injection will fail.
  • Injection D

    always returns the same instance DImpl

    .
  • The input DImpl

    will return a new instance each time and each will be different from the one that is returned D

    .
  • Injection E

    will return the same instance EImpl

    every time.
  • Input EImpl

    will also retrieve the same instance E

    .

This provides some flexibility. Imagine a hypothetical Cache

in which to store a certain number of objects, which have recently been extracted, where you want to have @User Cache

and @Product Cache

both injection. If you do bind(Cache.class).in(Singleton.class)

, you will have one shared cache between objects (and any naked Cache

injection), whereas if you do bind(Cache.class).annotatedWith(User.class).to(Cache.class).in(Singleton.class)

, then the annotated key will be stored in a one-point scope and each type of object will have its own cache.

+12


source







All Articles