web-dev-qa-db-ja.com

スプリング循環参照の例

私は春を使用して仕事で私のプロジェクトの1つに循環参照を持っていますが、修正することはできず、起動時に次のエラーで失敗します:

'org.springframework.security.authenticationManager': Requested bean is currently in creation: Is there an unresolvable circular reference?

サンプルプロジェクトの小さなレベルで同じ問題を再現しようとしました(作業プロジェクトのすべての詳細なしで)。しかし、春がエラーで失敗するもっともらしいシナリオを思い付くことができませんでした。私が持っているものは次のとおりです。

public class ClassA {
    @Autowired
    ClassB classB;
}

public class ClassB {
    @Autowired
    ClassC classC;
}

@Component
public class ClassC {
    @Autowired
    ClassA classA;
}

@Configuration
public class Config {
    @Bean
    public ClassA classA() {
        return new ClassA();
    }

    @Bean
    public ClassB classB() {
        return new ClassB();
    }
}

私のプロジェクトにも同様のシナリオがありますが、失敗しますが、サンプルプロジェクトでも同様に春が不平を言うと予想していました。しかし、それはうまくいきます!誰かが循環参照エラーでスプリングを破る方法の簡単な例を教えてもらえますか?

編集: javax.inject.Providerを使用して問題を修正しました。 2つのプロジェクトにおける他の唯一の違いは、使用されるアノテーションが@Autowiredと@Componentの代わりにjavax.inject.Injectとjavax.annotation.ManagedBeanであったことです。

26
robbin

これは古いスレッドなので、この問題をほとんど忘れていたと思いますが、その謎についてお知らせしたいと思います。私は同じ問題に遭遇し、私のものは魔法のように消えなかったので、問題を解決しなければなりませんでした。あなたの質問を段階的に解決します。

1。循環参照例外を再現できなかったのはなぜですか?

Springが処理します。必要に応じてBeanを作成して注入します

2。では、なぜプロジェクトで例外が発生するのですか?

  • @sperumalが言ったように、コンストラクタインジェクションを使用すると、Springは循環例外を生成する場合があります
  • ログによると、プロジェクトでSpring Securityを使用しています
  • Spring Security configでは、コンストラクターインジェクションを使用します
  • authenticationManagerを注入するBeanには循環参照がありました

3。では、なぜ例外は神秘的に消え去ったのでしょうか?

例外が発生する場合と発生しない場合は、Beanの作成順序によって異なります。いくつかの*context.xmlファイルを作成し、web.xmlで以下のような設定でそれらをロードすると思います

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:*-context.xml</param-value>
</context-param>

XmlファイルはXmlWebApplicationContextクラスによってロードされ、ファイルのロード順序は保証されません。ファイルシステムからファイルをロードするだけです。問題はここにあります。 BeanがSpring Securityの構築注入に使用されるときにすでに作成されているため、クラスが最初にアプリケーションコンテキストファイルをロードする場合、問題はありません。ただし、Springが最初にSpring Securityコンテキストファイルをロードすると、作成される前にSpringがコンストラクターインジェクションでBeanを使用しようとするため、循環参照の問題が発生します。

4。問題の解決方法

Xmlファイルの読み込み順序を強制します。私の場合、<import resource="">を使用して、アプリケーションコンテキストファイルの最後にセキュリティコンテキストxmlファイルをロードしました。ロード順序は、同じコードを使用している場合でも環境に応じて変更できるため、潜在的な問題を削除するように順序を設定することをお勧めします。

26
Sanghyun Lee

@Lazyを使用して、Beanが遅延的に作成され、自動配線の熱心なサイクルが中断されることを示すことができます。

アイデアは、サイクル上の一部のBeanをプロキシとしてインスタンス化でき、実際に必要になった瞬間に初期化されるというものです。つまり、プロキシであるBeanを除くすべてのBeanが初期化されます。初めて使用すると設定がトリガーされ、他のBeanはすでに設定されているため、問題にはなりません。

Spring-Jiraの1つの問題から:

@Configurationと併用して、その構成クラス内のすべてのBeanを遅延初期化する必要があることを示す@Lazyアノテーション。もちろん、@ Lazyを個々の@Beanメソッドと組み合わせて使用​​して、レイジー初期化を1つずつ行うこともできます。 https://jira.springsource.org/browse/SJC-26

Beanに@Lazyとして注釈を付けるだけで十分であることを意味します。または、次のように@Lazyとして構成クラスに注釈を付けるだけの場合:

@Configuration
@Lazy
public class Config {
    @Bean
    public ClassA classA() {
        return new ClassA();
    }

    @Bean
    public ClassB classB() {
        return new ClassB();
    }
}

Beanのインターフェースを実装する場合、これは非常にうまく機能します。

26

Springのドキュメントによると、constructor injectionを使用して、循環依存の問題またはBeanCurrentlyInCreationExceptionを取得することができます。

この問題を解決する解決策は、コンストラクター注入の代わりにセッターを使用することです。

リファレンス http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html

9
sperumal

問題に関するいくつかの読書:

http://blog.jdevelop.eu/?p=382

このような循環依存関係はクールではなく、可能な場合は回避する必要があります

2