6

この質問は、クラスが挿入されたフレームワークにguiceを使用することの続きであり、初期化する適切な方法は何ですか?、これを実装しようとしましたが、問題を回避するために他の方法も試しましたが、これまでのところ何も機能していません。

主な問題はこれです。APIのさまざまな部分で公開されているとInterfaceAがあります。InterfaceBこれらのインターフェイスの両方を実装する2つのクラスがありTestClassRealClassテストしているのか他のことをしているのかに応じて、次のことができます。

bind(InterfaceA.class).to(TestClass.class);
bind(InterfaceB.class).to(TestClass.class); 

または、本番用:

bind(InterfaceA.class).to(RealClass.class);
bind(InterfaceB.class).to(RealClass.class);

これらのクラスを使用するには、次の2つの要件があります。

  1. およびのすべてのインジェクションにバインドされる、TestClassまたはの同じインスタンスが必要です。したがって、シングルトンパターンのように、次の点を除きます。RealClassInterfaceAInterfaceB
  2. シングルトンは特定のスコープまたは子インジェクター専用であり、その多くはプログラムの実行中に作成されます。

デフォルトのスコープなしのアプローチでは、インターフェイスインジェクションごとにRealClass/の複数のインスタンスが作成されます。TestClass私はそれを望まないので、スコープ、子インジェクター、およびその他の方法でこれを実装しようとしました。何も機能していません:

  • 子インジェクターアプローチ:新しいインジェクターを作成し、TestClassまたはRealClassをそのインジェクターのシングルトンインスタンスにバインドしようとします。問題は、使用されているか使用されているTestClassRealClassが親インジェクターで構成されているかどうかであり、シングルトンであるため、すでにインスタンス化されています(での場合を除くStage.DEVELOPMENT)。InterfaceAたとえば、親インジェクターでにバインドしTestClassてから、子インジェクターでシングルトンとして再バインドする方法はありません。
  • スコープアプローチ:カスタムスコープを作成し、注釈TestClassを付けRealClassます。次に、このスコープに出入りして、そのスコープ内の単一のインスタンスを取得します。問題は、私のコードがマルチスレッドであり、1つのスレッドからスコープを変更すると、グローバルインジェクターが認識できる内容に影響を与え、他のインスタンスの作成を台無しにすることです。
  • チャイルドインジェクターとスコープアプローチの組み合わせ。このカスタムスコープを使用するたびに子インジェクターを作成しようとしましたがRealClass、親でのバインドが失敗します。

    No scope is bound to name.package.WhateverScope.
    

    WhateverScopeチャイルドインジェクターだけでなく、いつでも利用できると主張しているようです。

これらの問題はすべて、使用するか親で使用するかを構成できる必要があるが、後で特定のオブジェクトグループに対してシングルトンとしてインスタンス化できるようにする必要があるという事実に起因しているようTestClassですRealClass。私はこれを成し遂げる方法について私の髪を引っ張っています!

ちなみに、Guiceスコープのドキュメントは恐ろしく、ほとんど理解できません。この記事は私をどこにでも連れて行った唯一の記事です:

4

1 に答える 1

5

投稿後 1 時間も経たないうちに、いくぶんブレークスルーが発生したことをお詫びします。

http://code.google.com/p/google-guice/wiki/CustomScopesで提供されているスレッドローカルスコープの実装を多少悪用することで、これを修正できたようです。子インジェクターを使用せずにこの問題を解決するには、ややクリーンな方法のようです。それが「適切」かどうかはわかりませんが。私はまだ他の答えを受け入れます。

これが私がしたことです。まず、スコープのインスタンスを 1 つ作成し、それを適切なアノテーションにバインドして、インジェクターで使用できるようにします。

ThreadLocalScope scope = new ThreadLocalScope();
bindScope(ExperimentScoped.class, scope);
bind(ThreadLocalScope.class).toInstance(scope);

次に、ドキュメントに記載されているように、スコープにシードされるすべてのタイプのキーに対して偽のプロバイダーをバインドする必要があります。

bind(SomeKey.class)
  .toProvider(ThreadLocalScope.<SomeKey>seededKeyProvider())
  .in(ExperimentScoped.class);
bind(SomeOtherKey.class)
  .toProvider(ThreadLocalScope.<SomeOtherKey>seededKeyProvider())
  .in(ExperimentScoped.class);

各スコープ内で区別したい他のスコープ可能なオブジェクトもいくつかあるかもしれないので、それらもバインドします。これらはTestClassRealClass上記です。SomeScopedClassで注釈が付けられたものもあるかもしれません@ExperimentScoped

bind(InterfaceA.class).to(TestClass.class).in(ExperimentScoped.class);
bind(InterfaceB.class).to(TestClass.class).in(ExperimentScoped.class);

bind(SomeInterface.class).to(SomeScopedClass.class);

最後に、スコープを使用して、異なるスレッドから並行して、相互に依存するオブジェクトの個別のセットを作成できます。同じインジェクターを使用している場合でも、各スレッドは次のようなことを実行できます。

ThreadLocalScope scope = injector.getInstance(ThreadLocalScope.class);      
scope.enter();

try {
    // Seed the seed-able keys
    scope.seed(SomeKey.class, keyInstance);
    scope.seed(SomeOtherKey.class, otherKeyInstance);    

    SomeScopedClass instance = injector.getInstance(SomeScopedClass.class);

    // Hooray! instance was injected with the seeds and created just for this scope!
}
finally {
    scope.exit(); // Throws away the scope and referenced objects.
}

私の場合、スコープを完全に破棄することができます。これは、スコープ内のオブジェクトのセットが適切に配線された後は追跡する必要がないためです。しかし、後でこのスコープに戻ってさらにオブジェクトを注入したい場合は、おそらくうまくいかないでしょう。

これが誰かを助けたことを願っています。Guice のスコープ ドキュメントはひどいものです。

于 2013-02-26T23:55:09.720 に答える