9

Dagger でカスタム スコープを作成するには?

ガイドラインはありますか?見つかりませんでした。

Vaadin アプリケーションを開発しており、カスタム スコープが必要になります。UiScoped のようなもの。

よろしくお願いします

4

1 に答える 1

29

Dagger は、Guice と同じ種類のメカニズムを使用してスコープを実行しません。具体的には、Dagger は Guice のようにスコープを透過的に処理しません。さまざまなスコープ アノテーション、1 つのインジェクター、および舞台裏のさまざまなインスタンス キャッシュを使用します。代わりに、2 つの原則を使用します。1 つ目は、@Singleton は「グラフごとに 1 つ」(JSR-330 の最も厳密な解釈) を意味し、2 つ目は、グラフを階層内でリンクできることです。

Dagger は、この階層的にリンクされたグラフのツリーを使用します。このツリーでは、モジュールを追加して plus() メソッドを介して拡張することでグラフを作成し、より短い寿命の「スコープ付き」グラフを作成します。これはチャイルド インジェクターに似ています。ここでの重要な原則は、拡張グラフのインスタンスは元のグラフのインスタンスを参照できますが、その逆はできないということです。したがって、寿命が短いという同心円状の性質は、可視性に反映されます。寿命の短いオブジェクトは、寿命の長いオブジェクトを見る (依存する) ことができますが、その逆はできません。したがって、リクエストの存続期間中存続するオブジェクトは、アプリケーションの存続期間中存続するオブジェクトを見ることができますが、その逆はできません。

キャッシュされたインスタンスの範囲をより狭くすることが期待されるのは、このメカニズムによるものです。

いくつかのモジュールでグラフを構成し、シングルトンがある場合、すべての依存オブジェクトに提供されるそのグラフに 1 つのインスタンスがキャッシュされます。plus() メソッドを介してそのグラフへの拡張を作成し、@Singleton アノテーション付きバインディングを含む他のモジュールで構成すると、これらの他のモジュールはグラフごとに 1 つになりますが、短い方のインスタンスごとに 1 つになります。ライブ ObjectGraph インスタンス。

たとえば、リクエストに応答するサーバーをシミュレートしてみましょう。ここでは、アプリの存続期間中存続するオブジェクトと、リクエストの存続期間が短い間だけ存続するオブジェクトが必要です。

@Module()
public class MyAppModule {
  @Provides ConnectionDictonary connectionDictionary() {
    return new ConnectionDictonary(System.getProperty("some.property"));
  }

  /** Stateless mockable utilities for this app */
  @Provides Util util() { new Util(); }

  @Provides @Singleton DataStore store() { 
    return new DataStore();
  }

  @Provides @Singleton ConnectionPool pool(DataStore store, ConnectionDictionary dict) { 
    try {
      return DataStore.connectionPool(dict, System.getProperty("pool.size"));
    } catch (Exception e) {
      // bad bad bad
      throw new RuntimeException("Could not connect to datastore.", e);
    }
  }

}

// This module "adds to" MyAppModule by adding additional graph elements in
// an extended graph.
@Module(injects=MyRequestEndpoint.class, addsTo = MyAppModule.class)
public class MyRequestModule {
  private Request req;
  public MyRequestModule(Request req) { this.req = req; }

  @Provides @Singleton RequestObject request() { return req; }

  @Provides @Singleton User user(ConnectionPool pool, Request req, Util util) {
    try {
      Connection conn = pool.obtain();
      // getUser cannot throw null;
      return util.getUser(conn, req.get("user.id"), Crypto.hash(req.get("pass")));
    } catch (UserNotFoundException e) {
      return User.UNKNOWN;
    } catch (Exception e) {
      throw new RuntimeException("Could not obtain a user.", e);
    } finally { 
      // TODO: try-with-resources in Java7
      pool.release();
    }
  }

}

public class MyRequestEndpoint {
  @Inject ConnectionPool pool;
  @Inject Request req;

  public Output performService() {
    try {
      Connection conn = pool.obtain();
      // ... does stuff with request
    } finally {
      conn.release();
    }
  }
}

public class MyApp {    
  public void main(String ... args) {
    graph = ObjectGraph.create(MyAppModule.class);
    new ServiceListener(graph).start(); 
  }
}

public ServiceListener {
  private final ObjectGraph appGraph;
  public ServiceListener(ObjectGraph appGraph) {
    this.appGraph = appGraph;
  }

  //... infrastructure for listening and building request/response objects, etc.

  public void serveRequest(Request req, Response res) {
    // Take the application-scoped graph and create another graph we will 
    // use in this request and throw away.
    ObjectGraph requestGraph = MyApp.graph().plus(new MyRequestModule(req));
    Output output = requestGraph.get(MyRequestEndpoint.class).performService();
    Util.populateResult(output, result);
    result.flush();
  }
}

この例では、各 MyRequestEndpoint は ConnectionPool の共有インスタンスを取得しますが、任意の 2 つの要求のエンドポイントは 2 つの異なる RequestObject を取得します。

これは、J2EE パターンで頭のてっぺんから構築された、ややばかげた例です。このように構造化しないこの些細なことは、適切なサーバー モデルのために強力な足場が必要になります。実際、Dagger プロジェクトはそのようなことを行う可能性があります (注入されたサービス オブジェクトと単一のディスパッチ サーブレットまたはフィルターを使用することを丁重にお勧めしますが)。

しかし、おなじみのモデルでより狭い範囲を示していることを願っています

キーは注釈ではなく、グラフの存続期間にあります。存続期間の短いグラフは、存続期間の長いグラフの「子」または「拡張」として作成します。これらのグラフでメモ化されたオブジェクトには、グラフ管理オブジェクトの有効期間 (またはスコープ) があります。

于 2013-06-04T16:32:15.407 に答える