web-dev-qa-db-ja.com

春にシングルトンの複数のインスタンスを作成しますか?

互いに自動配線するSpringBeanのグラフがあります。非常に簡略化された図:

_<context:annotation-config/>
<bean class="Foo"/>
<bean class="Bar"/>
<bean class="Baz"/>

...

public class Foo {
   @Autowired Bar bar;
   @Autowired Baz baz;
}

public class Bar {
   @Autowired Foo foo;
}

public class Baz {
   @Autowired Foo foo;
}
_

これらのBeanはすべて、シングルトンであることを意味するスコープが指定されていません(明示的なシングルトンにしても、何も変更されません。私は試しました)。

問題は、単一のアプリケーションコンテキストのインスタンス化後、BarBazのインスタンスにFooの異なるインスタンス。これはどのように起こりますか?

Fooのpublicno argsコンストラクターを作成しようとしましたが、デバッグにより、Fooが複数回作成されていることが確認されました。これらすべての作成のスタックトレースは ここ です。

また、Springのデバッグログを有効にしようとしましたが、他のすべての行の中で、次のようになりました。

_DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
_

私のBeanが相互参照していることは理解していますが、Springフレームワークがシングルトンスコープを尊重し、シングルトンBeanを一度初期化してから、必要な人に自動配線することを期待しています。

古い学校のprivateコンストラクターを_public static Foo getInstance_アクセサーと一緒に使用すると、これは問題なく機能します。コンテキストのセットアップ中に例外はスローされません。

FWIW、私はo.s.c.s.ClassPathXmlApplicationContext(String ...configLocations)コンストラクターでSpringバージョン3.0.5(3.1.2でも試して、同じ結果)を使用しています。

静的初期化子を使用するようにコードを簡単に変換できますが、Springがこのように動作する理由を理解したいと思います。これはバグですか?

編集:いくつかの追加調査により、

  • アプリケーションコンテキストが初期化された後、context.getBean(Foo.class)alwaysへの後続のすべてのリクエストは、Fooの同じインスタンスを返します。
  • _@Autowired_をセッター(このBeanの約20回の使用)に置き換えても、このオブジェクトは複数構築されますが、すべての依存関係には同じが注入されます参照。

上記の私には、これは_@Autowired_の実装に関連するSpringのバグであることが示唆されています。 Springコミュニティフォーラムに投稿し、何か役立つものがあればここに投稿します。

16
mindas

Context:component-scanアノテーションに注意しない場合、子コンテキストは同じシングルトンBeanを再インスタンス化できます(MVCアノテーションなどの他のSpringコンテキストスキャンアノテーションもあります)。これは、WebアプリケーションでSpringサーブレットを使用する場合の一般的な問題です。 DispatcherServletが別のアプリケーションコンテキストを作成する理由 を参照してください。

子コンテキストでコンポーネントを再スキャンしていないこと、または特定のパッケージ/注釈のみをスキャンして、ルートコンテキストコンポーネントスキャンからそのパッケージ/注釈を除外していることを確認してください。

13
rootkit

何らかの理由で、統合テストとサービスでもこれがランダムにポップアップします(春のバージョン4.1.4、Java 1.8)。

複数の原因があるようです-最初は自動配線が原因であるように見えました。

ただし、影響を受ける各Beanに「id」フィールドを指定することで、最も一貫性のある障害を解決しました。

1
Andy

私のSpring構成は次のようでした:

<context:annotation-config/>

<bean class="Bar" />
<bean class="Foo" />
<bean class="Baz" /> 

クラスはあなたと同じです

次のようなテストアプリ:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/spring/testctx.xml");

        Foo foo = ctx.getBean(Foo.class);
        Baz baz = ctx.getBean(Baz.class);
        Bar bar = ctx.getBean(Bar.class);

        System.out.println(foo.equals(baz.foo));
        System.out.println(foo.equals(bar.foo));
        System.out.println(baz.equals(foo.baz));

        System.out.println(foo.baz.toString());
        System.out.println(baz.toString());
        System.out.println(foo.bar.toString());
        System.out.println(bar.toString());

    }

}

次のようなテストアプリからの出力:

true
true
true
Baz@8aef2b
Baz@8aef2b
Bar@215bf054
Bar@215bf054

3.0.6を使用すると、完全に正常に機能します(シングルトンBeanは確かにシングルトンです)。ここで説明しなかったことが、構成を台無しにしている可能性があります。もちろん、補足として、デフォルトのパッケージを使用すると、いくつかの不思議な魔法が発生する可能性があります;-)

0
Michal Pasinski

コンストラクターの代わりにセッターインジェクションを使用して、それが機能するかどうかを確認してください。春のBean xmlで、BeanAからBeanBへの参照を指定します。その逆も同様です。

0
Giri