12

Guice のシングルトンのインスタンス化がどのように機能するかを理解するのに苦労しています。利用可能なドキュメント (ここ - http://code.google.com/p/google-guice/wiki/Scopes ) を読みましたが、まだいくつかのことがわかりません:

  1. Guice を Tomcat に統合し、ServletModule にいくつかのバインディングをセットアップしました。

    bind(MyServlet.class).asEagerSingleton();
    serve("myUrl").with(MyServlet.class);
    serve("myOtherUrl").with(MyOtherServlet.class);
    

    (ここで MyOtherServlet クラスには @Singleton アノテーションが上にあります) ここでの私の意図は、2 つのサーブレットを用意することでした。一方は積極的にインスタンス化され、もう一方はそうではありません。ただし、そのクラスが熱心なシングルトンとしてバインドされていない場合でも、「serve ... with ...」行はサーブレットオブジェクトを自動的にインスタンス化するようです。上に添付したリンクは、Stage.Development と Stage.Production で実行されている Guice の違いについて言及していますが、Stage.Development を明示的に使用した場合でも、これは依然として発生しました (これはとにかくデフォルトです)。これを回避する方法はありますか?

  2. (1 に続く) すべてのサーブレットが熱心にインスタンス化されるようになったとしても、MyServlet が最初にインスタンス化されるようにするために、インジェクターを作成するときにモジュール (およびバインディング ステートメント) の順序を変更して、MyServlet のバインディングが最初に表示されるようにしました。ただし、次の形式の他のバインディング (サーブレット以外のクラス) よりも後でインスタンス化されることがわかりました。

    bind(MyInterface.class).to(MyClass.class).asEagerSingleton()
    

    これらの他のバインディングは、モジュール/バインディングの順序で後で表示されますが。私が調べたところ、Guice は「bind... asEagerSingleton()」のフォームを実行する前に、「bind... to... asEagerSingleton()」の形式でバインドされた熱心なシングルトンを単純にインスタンス化することがわかりました。そのため、次の行を変更して解決しました。

    bind(MyServlet.class).asEagerSingleton();
    

    の中へ:

    bind(MyServletDummyInterface.class).to(MyServlet.class).asEagerSingleton()
    

    そしてそれは実際に機能しました。それでも、これを解決するためだけにダミーのインターフェースを使用することは避けたいので、誰かがこれに対するより良い解決策を持っているかどうか疑問に思っていました..?

  3. 2 つの Guice モジュールがあります。1 つは ServletModule で、もう 1 つは AbstractModule です。ServletModule configureServlets() には、次のバインディングがあります。

    serve("aUrl").with(SomeServlet.class); AbstractModule の configure() には、次のバインディングがあります。

    bind(SomeImpl.class).asEagerSingleton();
    bind(SomeInterface.class).to(SomeImpl.class).in(Singleton.class);
    

さらに、 SomeServlet クラスには SomeInterface 型の注入されたフィールドがあり、クラスの上に @Singleton アノテーションがあります。

ここで、インジェクターを作成すると、SomeImpl クラスがインスタンス化され、同じインスタンスが SomeServlet インスタンスに注入されることが予想されます。前に述べたように、"serve... with..." ステートメントでバインドされたサーブレットも積極的にインスタンス化されるように見えますが、いずれにしてもインスタンス化される SomeImpl オブジェクトは 1 つだけです。しかし、何らかの理由で、これを実行すると 2 つの SomeImpl オブジェクトがインスタンス化されました。これを回避するために、configure() の 2 行を少し混ぜて、上記の代わりに次の行を追加しました。

bind(SomeImpl.class).in(Singleton.class)
bind(SomeInterface.class).to(SomeImpl.class).asEagerSingleton();

その後、正常に動作し、インスタンス化された SomeImpl のインスタンスが 1 つだけになりました。なぜスイッチが重要なのかはよくわかりません.後者の方法が「より良い」方法であることはわかりますが、両方が正しく機能することを期待しているので、ここで何か問題があるのではないかと思っています.. .

4

1 に答える 1

13

1) これを回避する方法はありません。なぜなら、Guice はinit()独自のフィルター パイプラインの初期化時にすべてのサーブレットのメソッドを呼び出し、それらすべてを構築するからです。このような遅延初期化ロジックが本当に必要な場合は、それをサーブレット自体に配置する必要があります (または、分離されたヘルパー クラスを使用するか、ユース ケースに応じてさまざまな方法があります)。

2) 一般的に言えば、Guice のモジュールはバインディングを宣言しますが、正確なインスタンス化順序を持つブートストラップ定義になるようには設計されていません。このように定義されたインスタンス化順序が必要な場合は、目的の順序でオブジェクトを自分で作成し、 を介してそれらをバインドしますbind(...).toInstance(...)。自己構築されたインスタンスで注入が必要な場合は、使用できますrequestInjection(...)(フィールド/メソッドの注入で十分な場合は、コンストラクターの注入の方が面倒です)。

3) Guice のスコープは、バインディング値ではなくバインディング キーに適用されます。スコープの適用では、2 番目の例だけが意図したとおりに機能する理由を説明しています。

于 2011-11-08T22:58:20.977 に答える