ダガー2の紹介

Dagger 2の概要

1. 前書き

このチュートリアルでは、高速で軽量な依存性注入フレームワークであるDagger2について説明します。

このフレームワークはJavaとAndroidの両方で使用できますが、コンパイル時インジェクションから派生した高性能により、Javaの主要なソリューションになります。

2. 依存性注入

ちょっとした注意として、Dependency Injectionは、プログラムのフローがプログラム自体によって制御される、より一般的な制御の反転の原則の具体的なアプリケーションです。

これは、他のオブジェクトに必要なオブジェクト(または依存関係)のインスタンスを提供する外部コンポーネントを介して実装されます。

そして、異なるフレームワークは、異なる方法で依存性注入を実装します。 特に、これらの違いの中で最も注目に値するものの1つは、インジェクションが実行時またはコンパイル時に発生するかどうかです。

ランタイムDIは通常、リフレクションに基づいており、使用は簡単ですが、ランタイムは遅くなります。 a run-time DI framework is Springの例。

一方、コンパイル時DIはコード生成に基づいています。 これは、コンパイル中にすべての重い操作が実行されることを意味します。 コンパイル時DIは複雑さを増しますが、一般的には高速に実行されます。

ダガー2はこのカテゴリーに分類されます。

3. Maven/Gradle Configuration

プロジェクトでDaggerを使用するには、pom.xmlthe dagger dependencyを追加する必要があります。


    com.google.dagger
    dagger
    2.16

さらに、アノテーション付きクラスをインジェクションに使用されるコードに変換するために使用されるinclude the Dagger compilerも必要になります。


    org.apache.maven.plugins
    maven-compiler-plugin
    3.6.1
    
         
              
                  com.google.dagger
                  dagger-compiler
                  2.16
              
         
    

この構成では、Mavenは生成されたコードをtarget/generated-sources/annotationsに出力します。

このため、コード補完機能のいずれかを使用する場合は、we likely need to further configure our IDEを使用します。 一部のIDEでは注釈プロセッサを直接サポートしていますが、他のIDEではこのディレクトリをビルドパスに追加する必要がある場合があります。

または、AndroidとGradleを使用している場合は、両方の依存関係を含めることができます。

compile 'com.google.dagger:dagger:2.16'
annotationProcessor 'com.google.dagger:dagger-compiler:2.16'

プロジェクトにDaggerが含まれているので、サンプルアプリケーションを作成して、その動作を確認しましょう。

4. 実装

この例では、コンポーネントを注入して車を作成しようとします。

現在、多くの場所でDagger uses the standard JSR-330 annotationsがあり、そのうちの1つは@Inject.です。

フィールドまたはコンストラクターに注釈を追加できます。 ただし、Dagger doesn’t support injection on private fieldsなので、カプセル化を維持するためにコンストラクターの注入を行います。

public class Car {

    private Engine engine;
    private Brand brand;

    @Inject
    public Car(Engine engine, Brand brand) {
        this.engine = engine;
        this.brand = brand;
    }

    // getters and setters

}

次に、インジェクションを実行するためのコードを実装します。 具体的には、次のものを作成します。

  • moduleは、オブジェクトの依存関係を提供または構築するクラスであり、

  • インジェクターを生成するために使用されるインターフェースであるcomponent

複雑なプロジェクトには複数のモジュールとコンポーネントが含まれる場合がありますが、非常に基本的なプログラムを扱っているため、それぞれ1つで十分です。

それらを実装する方法を見てみましょう。

4.1. モジュール

モジュールを作成するには、we need to annotate the class with the @Module annotation。 この注釈は、クラスがコンテナで依存関係を利用できることを示しています。

@Module
public class VehiclesModule {
}

次に、we need to add the @Provides annotation on methods that construct our dependencies

@Module
public class VehiclesModule {
    @Provides
    public Engine provideEngine() {
        return new Engine();
    }

    @Provides
    @Singleton
    public Brand provideBrand() {
        return new Brand("example");
    }
}

また、特定の依存関係のスコープを構成できることに注意してください。 この場合、Brandインスタンスにシングルトンスコープを指定して、すべての車のインスタンスが同じブランドオブジェクトを共有するようにします。

4.2. 成分

次に、コンポーネントインターフェイスを作成します。これは、VehiclesModuleによって提供される依存性を注入して、Carインスタンスを生成するクラスです。

簡単に言えば、Carwe need to mark the class with the @Component annotationを返すメソッドシグネチャが必要です。

@Singleton
@Component(modules = VehiclesModule.class)
public interface VehiclesComponent {
    Car buildCar();
}

モジュールクラスを引数として@Componentアノテーションに渡した方法に注目してください。 If we didn’t do that, Dagger wouldn’t know how to build the car’s dependencies.

また、モジュールはシングルトンオブジェクトを提供するため、Dagger doesn’t allow for unscoped components to refer to scoped bindingsであるため、コンポーネントに同じスコープを指定する必要があります。

4.3. クライアントコード

最後に、アノテーションプロセッサをトリガーしてインジェクターコードを生成するために、mvn compileを実行できます。

その後、インターフェースと同じ名前で、接頭辞「Dagger」が付いたコンポーネントの実装が見つかります。

@Test
public void givenGeneratedComponent_whenBuildingCar_thenDependenciesInjected() {
    VehiclesComponent component = DaggerVehiclesComponent.create();

    Car carOne = component.buildCar();
    Car carTwo = component.buildCar();

    Assert.assertNotNull(carOne);
    Assert.assertNotNull(carTwo);
    Assert.assertNotNull(carOne.getEngine());
    Assert.assertNotNull(carTwo.getEngine());
    Assert.assertNotNull(carOne.getBrand());
    Assert.assertNotNull(carTwo.getBrand());
    Assert.assertNotEquals(carOne.getEngine(), carTwo.getEngine());
    Assert.assertEquals(carOne.getBrand(), carTwo.getBrand());
}

5. 春のアナロジー

Springに詳しい人は、2つのフレームワークの類似点に気付いているかもしれません。

Daggerの@Moduleアノテーションは、Springのステレオタイプアノテーション(たとえば、@Service@Controller…)と非常によく似た方法でコンテナにクラスを認識させます。 同様に、@Provides@Componentは、それぞれSpringの@Bean@Lookupとほぼ同等です。

Springには@Singletonに相関する@Scopeアノテーションもありますが、Springはデフォルトでシングルトンスコープを想定しているのに対し、DaggerはデフォルトでSpring開発者がプロ​​トタイプスコープと呼んでいるものを呼び出しているという別の違いに注意してください。依存関係が必要になるたびにプロバイダーメソッド。

6. 結論

この記事では、基本的な例を使用してDagger 2をセットアップして使用する方法を説明しました。 また、ランタイム注入とコンパイル時注入の違いも考慮しました。

いつものように、記事のすべてのコードはover on GitHubで利用できます。