2017-11-03 13 views
8

Spring 3.X.Xを使用する2つのサービスに@Primaryというアノテーションが付けられており、別の設定クラスを作成しました。SpringはBeanの設定を「プライマリ」に設定します。

何らかの理由で、構成クラスのデバッグ中に無視されますが、正しい依存関係が得られることがわかりますが、使用するときに間違ったものが設定されています。

インタフェースはFoo::

@Primary 
@Service("FooImpl") 
public class FooImpl implements Foo { 

    private String message = "fooDefaultMessage"; 

    @Override 
    public String getMessage() { 
     return message; 
    } 

    public void setMessage(String message) { 
     this.message = message; 
    } 
} 

バーインターフェース:ハードコードデフォルトメッセージと

public interface Foo { 
    String getMessage(); 
} 

プライマリ実装

が、私はそれが簡単にコードを説明することを見つける、ここでの例です:

public interface Bar { 

    void doBar(); 
} 

バーのデフォルトの実装:

@Primary 
@Service("BarImpl") 
public class BarImpl implements Bar { 

    private Foo foo; 

    @Override 
    public void doBar() { 
     System.out.println(foo.getMessage()); 
    } 

    public Foo getFoo() { 
     return foo; 
    } 

    @Autowired 
    public void setFoo(Foo foo) { 
     this.foo = foo; 
    } 
} 

これまでのところは良い、私は予想通り、私はすべてを取得バーを注入したい場合。事は、私は次のように設定を持っている:

@Configuration 
public class BeanConfiguration { 

    @Bean 
    @Qualifier("readOnlyFoo") 
    Foo readOnlyFoo() { 
     FooImpl foo = new FooImpl(); 
     foo.setMessage("a read only message"); 
     return foo; 
    } 

    @Bean 
    @Qualifier("readOnlyBar") 
    Bar readOnlyBar() { 
     BarImpl bar = new BarImpl(); 
     bar.setFoo(readOnlyFoo()); 
     return bar; 
    } 
} 

私はデフォルトのFooの代わりに、ここで設定1を取得していますreadOnlyBarを注入する場合。

private Bar readOnlyBar; 

@Autowired 
@Qualifier("readOnlyBar") 
public void setReadOnlyBar(Bar readOnlyBar) { 
    this.readOnlyBar = readOnlyBar; 
} 

... 
readOnlyBar.doBar(); 

"fooDefaultMessage"でFoo Beanを持っていますか?何故ですか? Springが@Configurationで設定したBeanを使用していることを確認するにはどうすればよいですか?事前に

おかげで、

EDIT:ノート代わりに@Configurationクラスの読み取り専用()メソッドを呼び出すことで、あなたが@Qualified引数を渡すと同じことが起こるということ。すなわち:

@Configuration 
public class BeanConfiguration { 

    @Bean 
    @Qualifier("readOnlyFoo") 
    Foo readOnlyFoo() { 
     FooImpl foo = new FooImpl(); 
     foo.setMessage("a read only message"); 
     return foo; 
    } 

    @Bean 
    @Qualifier("readOnlyBar") 
    Bar readOnlyBar(@Qualifier("readOnlyFoo") Foo readOnlyFoo) { 
     BarImpl bar = new BarImpl(); 
     bar.setFoo(readOnlyFoo); 
     return bar; 
    } 
} 

私は私が/欲しい期待するが、残念ながら、私はそれを使用することはできませんとしてすべての作品コンストラクタ依存性注入を使用してみてください代わりに場合。

+0

プロファイルを使用できませんか? –

+0

ここでプロファイルがどのように役立つか分かりません。はい、既定の実装を使用するプロファイルと読み込み専用のプロファイルを指すプロファイルを持つことができます。問題は、読み取り専用の新しい(読み取り専用の)Beanをインスタンス化する読み取り専用インスタンスをデフォルトから設定する方法です。 – void

答えて

2

@Autowiredをインスタンス変数に使用することはできません。その場合は、@Beanメソッドで設定します。春のライフサイクルの一部は

ビーン定義スキャン=>作成されたBeanインスタンス=>ポストプロセッサと呼ばれる=> .....

あなたの例では、

@Bean 
@Qualifier("readOnlyBar") 
Bar readOnlyBar() { 
    BarImpl bar = new BarImpl(); 
    bar.setFoo(readOnlyFoo()); 
    return bar; 
} 

readOnlyBar Beanが取得この道を行きますこのメソッド内からreadOnlyFoo()が呼び出されるため、readOnlyFoo beanもインスタンス化されます。この時点まで、readOnlyBarのインスタンス変数にreadOnlyFooがあります。 Beanがインスタンス化されると、AutowiredAnnotationBeanPostProcessorが呼び出され、インスタンス変数またはメソッドの@Autowired注釈があればBeanのクラス(この場合はBarImpl)をスキャンします。フィールドインジェクションまたはセッター注入(@Autowired注釈がある場合はどこでも)を使用して、それらを見つけて対応する変数に豆を注入しようとします。この場合、@Autowiredセッターがあり、@Qualifier注釈が指定されていないため、スプリングはdefaultFooMessage beanの@Primary beanを挿入します。

AFAIKでは、自動ワイヤリングよりも優先する方法として、春に設定する方法はありません。@Beanの方法が優先されます。

すべての豆を@Beanメソッドでインスタンス化すると、問題が解決されます。

2

通常、Beanと修飾子の2つの注釈の代わりに@Bean( "beanName")を使用する方がよいでしょう。そして、私はBeanの命名にQualifierが機能するのかどうかはわかりません。とにかくコードを一つのスタイルで書くべきです。したがって、@Serviceアノテーションでvalue属性を使用する場合は、@ Beanアノテーションでvalue属性を使用する必要があります。

フィールド@Autowired List<Foo> allFoosを作成し、デバッグモードで表示します。 Foo beanがすべて表示されるので、名前を確認できます。

2

@ yaswanthは彼の答えで指摘したように、問題は、Beanの作成後に起こったプロパティ注入によって、fooプロパティが上書きされたことでした。

これを回避する方法の1つは、特性注入の代わりにBarImplのコンストラクタ注入を使用することです。それは...のような

@Primary @Service("BarImpl") 
class BarImpl implements Bar 
{ 
    private Foo foo; 

    @Autowired 
    public BarImpl(Foo foo) { 
     this.foo = foo; 
    } 
} 

をあなたのコードを見てになるだろうし、あなたの設定は、サイドトラックとして...

@Configuration 
class BeanConfiguration 
{ 
    @Bean @Qualifier("readOnlyFoo") 
    Foo readOnlyFoo() { 
     FooImpl foo = new FooImpl(); 
     foo.setMessage("a read only message"); 
     return foo; 
    } 

    @Bean @Qualifier("readOnlyBar") 
    Bar readOnlyBar(@Qualifier("readOnlyFoo") Foo readOnlyFoo) { 
     return new BarImpl(readOnlyFoo); 
    } 
} 

だろう。ファクトリメソッドを明示的に呼び出すのではなく、ファクトリメソッドで依存関係注入を確実に使用するようにする必要があります。

あなたの将来の努力に幸運を祈る!

+0

私はこれを知っていましたが、質問に書かれているように、それは私が必要としたものに最も近い答えであり、恩恵は終わりそうです。したがって、私は賞金を受け取るためにこの答えを選びました。 – void

関連する問題