16

相互に自動配線する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はすべて、シングルトンであることを意味するスコープが指定されていません(明示的なシングルトンにしても、何も変更されません。私は試しました)。

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

public no argsコンストラクターを作成しようとしましたがFoo、デバッグ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) 常に同じインスタンスを返しますFoo
  • @Autowiredセッター(このBeanの約20回の使用)で置き換えても、このオブジェクトは複数構築されますが、すべての依存関係に同じ参照が挿入されます。

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

4

4 に答える 4

13

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

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

于 2013-02-12T17:10:52.343 に答える
1

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

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

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

于 2016-06-29T11:50:12.027 に答える
0

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

于 2012-07-18T19:02:58.603 に答える
0

私の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は確かにシングルトンです)。ここで説明しなかったことが、構成を台無しにしている可能性があります。もちろん、補足として、デフォルトのパッケージを使用すると、不思議な魔法が発生する可能性があります;-)

于 2012-11-29T00:42:22.880 に答える