(八) Dagger2 @Singleton案例分析

代碼示例
class Tiger {
    public void sleep() {
        System.out.println("Tiger sleeping");
    }
}
@Module
class ZooModule {
    @Singleton // 注意這裏
    @Provides
    public Tiger providerTiger() {
        return new Tiger();
    }
}
@Singleton // 注意這裏
@Component(modules = {ZooModule.class})
interface ZooComponent {
    Zoo inject(Zoo zoo);
}
public class Zoo {
    @Inject
    Tiger tiger;
    @Test
    public void 案例八() {
        DaggerZooComponent.create().inject(this);
        tiger.sleep();
    }
}
Dagger2生成代碼閱讀

主要分析加了@Singleton註解之後,Tiger對象在同一個注射器生命週期中是一個單例對象.

就着上面的案例來看下Degger2生成的代碼,生成的代碼在build\generated\sources\annotationProcessor\..文件夾中.

  1. DaggerZooComponent.create()
final class DaggerZooComponent implements ZooComponent {
    private Provider<Tiger> providerTigerProvider;
    private DaggerZooComponent(ZooModule zooModuleParam) {
        // 該方法最終創建一個Provider對象,它持有ZooModule_ProviderTigerFactory對象.
        initialize(zooModuleParam);
    }
    private void initialize(final ZooModule zooModuleParam) {
        // ZooModule_ProviderTigerFactory.create(zooModuleParam)創建一個ZooModule_ProviderTigerFactory對象,它的父類其實是Provider.
        // DoubleCheck.provider():創建DoubleCheck對象.
        this.providerTigerProvider = DoubleCheck.provider(ZooModule_ProviderTigerFactory.create(zooModuleParam));
    }
    static final class Builder {
        private ZooModule zooModule;
        private Builder() {
        }
        public Builder zooModule(ZooModule zooModule) {
          this.zooModule = Preconditions.checkNotNull(zooModule);
          return this;
        }
        // 創建注射器對象
        public static ZooComponent create() {
            return new Builder().build();
        }
        public ZooComponent build() {
          if (zooModule == null) {
            // ZooModule對象在這裏被創建
            this.zooModule = new ZooModule();
          }
          // 創建注射器對象DaggerZooComponent.
          return new DaggerZooComponent(zooModule);
        }
    }
}
  1. 注入對象前需要弄清除DoubleCheck.provider()
    首先看ZooModule_ProviderTigerFactory.create(zooModuleParam)
public final class ZooModule_ProviderTigerFactory implements Factory<Tiger> {
    // 該方法主要用來創建ZooModule_ProviderTigerFactory對象,它的父類其實是Provider.
    public static ZooModule_ProviderTigerFactory create(ZooModule module) {
      return new ZooModule_ProviderTigerFactory(module);
    }
}

再看下DoubleCheck.provider()

public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
    public static <P extends Provider<T>, T> Provider<T> provider(P delegate) {
      ...
      // delegate:是ZooModule_ProviderTigerFactory對象,他的父類是Provider.
      return new DoubleCheck<T>(delegate);
    }
    // 它最終將ZooModule_ProviderTigerFactory對象存儲起來了.
    private DoubleCheck(Provider<T> provider) {
      assert provider != null;
      this.provider = provider;
    }
}
  1. .inject(this)
final class DaggerZooComponent implements ZooComponent {
    @Override
    public Zoo inject(Zoo zoo) {
        return injectZoo(zoo);
    }
    private Zoo injectZoo(Zoo instance) {
        // providerTigerProvider.get():這裏是Tiger對象單例的關鍵所在
        // Zoo_MembersInjector.injectTiger():真實的賦值動作在該方法中
        Zoo_MembersInjector.injectTiger(instance, providerTigerProvider.get());
        return instance;
    }
}
  1. providerTigerProvider.get()
    上面分析過providerTigerProvider是一個Provider對象,它持有ZooModule_ProviderTigerFactory對象,下面先看Provider.get()
public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
    private DoubleCheck(Provider<T> provider) {
      assert provider != null;
      this.provider = provider; // 該變量爲ZooModule_ProviderTigerFactory對象.
    }
    @Override
    public T get() {
      Object result = instance;
      if (result == UNINITIALIZED) {
        synchronized (this) {
          result = instance;
          if (result == UNINITIALIZED) {
            // 經過雙重判斷,如果result爲null,
            // 那麼就調用ZooModule_ProviderTigerFactory.get()獲取tiger對象賦值給result變量
            result = provider.get();
            instance = reentrantCheck(instance, result);
            provider = null;
          }
        }
      }
      // 最終將tiger對象返回
      return (T) result;
    }
}
  1. ZooModule_ProviderTigerFactory.get()
public final class ZooModule_ProviderTigerFactory implements Factory<Tiger> {
    @Override
    public Tiger get() {
      return providerTiger(module);
    }
    public static Tiger providerTiger(ZooModule instance) {
      //  ZooModule_ProviderTigerFactory.get()最終調用的方法是 ZooModule.providerTiger(),最終返回Module創建的tiger對象.
      return Preconditions.checkNotNull(instance.providerTiger(), "Cannot return null from a non-@Nullable @Provides method");
    }
}
  1. Zoo_MembersInjector.injectTiger(instance, providerTigerProvider.get())
    最終的賦值動作在該方法中
public final class Zoo_MembersInjector implements MembersInjector<Zoo> {
    @InjectedFieldSignature("com.yey.dagger2.Zoo.tiger")
    public static void injectTiger(Zoo instance, Object tiger) {
      instance.tiger = (Tiger) tiger;
    }
}
總結
  1. Module中增加了@Singleton註解,那麼依賴該Module的注射器也得增加@Singleton註解,否則報錯.
  2. Module中方法增加@Singleton註解,當前方法返回的對象時,會對該返回的對象進行雙重檢查,保證該對象是單例.
  3. @Singleton註解是與每個注射器的生命週期同步,兩個不同的注射器其實會創建兩個tiger對象,但是在同一個注射器下,tiger對象纔是單例.
注射器相互依賴時使用@Scope
class Tiger {
    public void sleep() {
        System.out.println("Tiger sleeping");
    }
}
@Module
class ZooModule {
    // 表示Tiger對象是單例.
    @Singleton
    @Provides
    public Tiger providerTiger() {
        return new Tiger();
    }
}
// ZooComponent注射器使用了@Singleton,當另外一個注射器依賴它時,也需要添加一個@Scope類型註釋.
@Singleton 
@Component(modules = {ZooModule.class})
interface ZooComponent {
    Tiger provider();
}
// 假如PlaygroundComponent注射器依賴ZooComponent注射器,因爲ZooComponent有@Singleton註釋,
// 所以PlaygroundComponent注射器也必須增加一個Scope註釋,並且不允許和@Singleton註釋相同,
// 那麼只有自定義一個@MyScope註釋
@MyScope
@Component(dependencies = {ZooComponent.class})
interface PlaygroundComponent {
    Playground inject(Playground playground);
}
//自定義一個MyScope註釋
@Scope
@Documented
@Retention(RUNTIME)
public @interface MyScope {}

其實@Singleton註釋和@MyScope功能是一樣的,只是名字不同而已,上面的代碼中將他們兩個調換完全可以.在同一個注射器的生命週期範圍裏,用@Singleton標註的方法獲取到的對象是一個單例.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章