Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dagger 2 singleton in multiple instances

I just tested out Dagger 2 and I am having some strange behaviour regarding the singleton annotation. I created some test code to show my problem.

My Module:

@Module
public class App {

    @Provides
    @Singleton
    ThingA provideThingA(){
        return new ConcreteThingA();
    }

}

Interface of the thing I want in singleton:

public interface ThingA {
    void showMyId();
}

Implementation:

public class ConcreteThingA implements ThingA {
    @Override
    public void showMyId() {
        System.out.println(this);
    }
}

Code that executes Dagger:

public void doStuff() {
    ThingA thingA=DaggerThingAComponent.create().provideThingA();
    ThingA thingB=DaggerThingAComponent.create().provideThingA();
    System.out.println("Hello");
}

And here is a screenshot showing that I do not get the same instance when I ask for it twice. Have I missed something fundamental? ThingA is just a silly name and in my actual application I would like to have this singleton behaviour on my services.

Debug screenshot

like image 650
why_vincent Avatar asked Sep 07 '16 17:09

why_vincent


People also ask

Can we create multiple instances of Singleton?

Singleton patten means only one instance is allowed. So there is no question of creating multiple instances. Though there are some hacks and workarounds like Serializing the Object and De Serializing it back or using different Class loaders but again it violates the basic principle why Singleton pattern is created for.

What is singleton in dagger?

Singleton allows you to have one instance of an object running across the whole application, and every time it is provided to a different class, the same instance of that object is injected.

Is dagger singleton thread safe?

Yes, @Singleton s in Dagger 2 are thread safe with double checked locking, same in Dagger 1. See ScopedProvider .

What is @component in dagger?

Components are essentially the glue that holds everything together. They are a way of telling Dagger 2 what dependencies should be bundled together and made available to a given instance so they can be used. They provide a way for a class to request dependencies being injected through their @Inject annotation.


1 Answers

The trick is that Dagger enforces scope/lifecycle through components, and you've created two separate components here:

ThingA thingA = DaggerThingAComponent.create().provideThingA();
ThingA thingB = DaggerThingAComponent.create().provideThingA();

Each time you create the new top-level @Singleton-annotated Component, Dagger creates a brand new object graph with a brand new container for each @Singleton object. You should have this instead:

ThingAComponent component = DaggerThingAComponent.create();
ThingA thingA = component.provideThingA();
ThingA thingB = component.provideThingA();  // thingA == thingB

Of course, anything further accessed through the dependency graph all comes from the same component, so this will preserve the singleton behavior you're looking for.


In most cases, you should not need to pass around the Component: The Component should be used for top-level components, and anything accessible through the injector should @Inject its dependencies (which means it shouldn't need a reference to the component itself). This might appear problematic during the migration to DI or Dagger, but creating multiple @Singleton components is not the way around it. Instead, try one of the following:

  • If you need multiple instances of something, you can always inject Provider<T> instead of T whether or not you've created a @Provides method. For that matter, you can inject a Lazy<T> if you only need zero or one copies of a particular dependency, particularly if the creation of that object is particularly heavy.
  • You can @Inject the component itself if you need it deep within the object graph, though it's always preferable to @Inject Provider<T> tProvider instead of @Inject YourComponent just to call YourComponent.getT.
  • In some cases, including Android, it may make sense to save the component to a globally-accessible field, either as an instance field in your Application or as a static field somewhere else. This is specifically because Android creates objects on its own, reflectively, rather than getting injected instances from the graph. For all other cases, inject your dependencies to avoid needing to pass around the component.

See also: Bindings in the graph from the Dagger 2 Users Guide

like image 63
Jeff Bowman Avatar answered Oct 02 '22 04:10

Jeff Bowman