2016-03-23 11 views
2

私は現在、多少のように、春のJavaの設定クラスを介して注入相互に依存するサービスを、持っているアプリケーションに取り組んでいます:春 - Javaの設定クラスの中ジェクトコンストラクタの引数

@Configuration 
public class ExampleConfiguration { 

    @Bean 
    public IFirstService firstService() { 
     return new FirstServiceImpl(); 
    } 

    @Bean 
    public ISecondService secondService() { 
     return new SecondServiceImpl(); 
    } 
} 

@Service 
public class FirstServiceImpl implements IFirstService{ 
    ... 
} 

@Service 
public class SecondServiceImpl implements ISecondService{ 

    @Inject 
    private IFirstService firstService; 

    ... 
} 

これはと、意図したとおりに働いていますアプリケーション全体で作成され注入される各サービスの単一のインスタンス。しかし、私はコンストラクタインジェクションに変換することに興味があります。ユニット/模擬テストパターンのサポートが向上するようです。

@Service 
public class SecondServiceImpl implements ISecondService { 

    private IFirstService firstService; 

    @Inject 
    public SecondServiceImpl(IFirstService firstService){ 
     this.firstService = firstService; 
    } 

    ... 
} 

私は、これは/は、上記構成のクラスと連携どのように相互作用するかを決定されるに実行している問題:私はそれを理解したように、このようなものにSecondServiceImplコードを変更します。

@Configuration 
public class ExampleConfiguration { 

    @Bean 
    public IFirstService firstService() { 
     return new FirstServiceImpl(); 
    } 

    @Bean 
    public ISecondService secondService() { 
     return new SecondServiceImpl(firstService()); 
    } 
} 

しかし、それは、アプリケーション全体に注入IFirstServiceの1つのインスタンスが存在すべきであるという考えを台無しにしてしまうようfirstService()への各呼び出しは新しいをインスタンス化するので、これは、ようだ:私はのようにこれを行う何かを見てきたすべての例IFirstServiceインスタンス。

Springがそのようなことを処理する方法や、依存関係の注入について間違っているかどうかについて詳しく知りませんか?任意の提案をいただければ幸いです!

EDIT:

受け入れ答えが正しいですが、私は最近、これを行うには、より堅牢な方法がある発見した - あなたは@Beanアノテーションを付けるメソッドのパラメータとして必要な項目を指定することができ、そしてそれは意志同一または他の利用可能な構成から注射することができる。そう上記なる:

@Configuration 
public class ExampleConfiguration { 

    @Bean 
    public IFirstService firstService() { 
     return new FirstServiceImpl(); 
    } 

    @Bean 
    public ISecondService secondService(IFirstService firstService) { 
     return new SecondServiceImpl(firstService); 
    } 
} 

特定のBean IDが必要な場合@Qualifier注釈は、メンバーパラメータでインラインで使用することができる。なお

答えて

1

設定クラスはそのまま使用されません。 Springはconfigをいわゆるproxy-classにラップします。このプロキシクラスは、オリジナルのコンフィグレーションクラスのメソッドのすべての呼び出しを傍受します。@Bean注釈が付いています。ここで

@Configuration 
public class ExampleConfiguration { 

    @Bean 
    public IFirstService firstService() { 
     return new FirstServiceImpl(); 
    } 

    @Bean 
    public ISecondService secondService() { 
     return new SecondServiceImpl(
       firstService() //actually here is will be invoked method of proxy class 
     ); 
    } 
} 

@Beanで注釈さfirstService()です:設定のコードを考えてみましょう。したがって、あなたの設定クラスがプロキシにラップされているので、firstService()を呼び出すと、プロキシのメソッドが呼び出されますが、元の設定クラスのメソッドは呼び出されません。

プロキシクラスの簡略化されたロジックは、次のようになります。プロキシクラスがメソッドの呼び出しを傍受すると、(singletoneの場合):すでにBeanのインスタンスが作成されているかどうかをチェックします。 Beanが存在する場合、このBeanが返されます。 Beanが存在しない場合、元のコンフィグレーションクラスのメソッドの呼び出しによって新しいインスタンスが作成されます。

これは、firstService()を呼び出すたびにが新しいIFirstServiceインスタンスをインスタンス化しないことを意味します。最初の呼び出し時に作成され、その後のすべての呼び出しで同じインスタンスが返されます。この例では、またはすべての状況で動作しない場合がありますデフォルトのシングルトンのプロトタイプを、使用していること

@Configuration 
public class ExampleConfiguration { 

    @Bean(name="first-service")      // #1 - put a name on it 
    public IFirstService firstService() { 
     return new FirstServiceImpl(); 
    } 

    @Bean 
    public ISecondService secondService(
          @Qualifier("first-service") // #2 - inject it here 
          IFirstService service { 
     return new SecondServiceImpl(service); 
    } 
} 

お知らせ:

0

スプリングは、構成フェーズ中に依存性注入を解決するCGLIBプロキシを使用。 firstService()の結果は、すべての依存関係が解決されて適切に注入されると、最初はプロキシになり、シングルトンとして統合されます。

1

@Qualifier注釈はあなたの友達です。たとえば、Beanファクトリを参照するたびにIFirstServiceシングルトンを使用する場合は、新しいISecondServiceインスタンスを作成する必要があります。あるいは、両方をプロトタイプBeanとして動作させたい場合もあります。

その後、あなたは、全体として、または特定のBean宣言で構成オブジェクトのためのスコープの賢明な利用を行う必要があります(今、これは完全に別のトピックである。)(代わりに使用@Named)

EDIT

実際、私の反応を広げてみましょう。 @Qualifierを使うことができますが、代わりに@Namedを使うことをお勧めします。

@Configuration 
public class ExampleConfiguration { 

    @Bean(name="first-service")      // #1 - put a name on it 
    public IFirstService firstService() { 
     return new FirstServiceImpl(); 
    } 

    @Bean 
    public ISecondService secondService(
          @Named("first-service") // #2 - inject it here 
          IFirstService service { 
     return new SecondServiceImpl(service); 
    } 
} 

なぜですか?

  1. 一つはJSR-330に付属しているものです:まあ、我々は@Qualifier注釈の2つのバージョンがあります。
  2. もう1つはone with Springです。

JSR-330 @Qualifierは、私の例のようにパラメータで使用することはできません。メソッドと属性に限定されています。

しかし、私の例のものはSpringに由来し、パラメータに適用できます。

一般的に、我々はJSR-330のアノテーションに固執したい(かもしれ春の注釈として罰金として。)だからのため、我々は代わりに1である@Namedを使用)JSR-330から、及び2)それは同等です春の@Qualifier

+0

JSR-330の修飾子がパラメータ – romeara

+0

で使用できなかったため、名前付き注釈を使用していただきありがとうございます - 私は春の注釈を使用せずにそのようなものを修飾する方法を知りました。私はこれを答えとして使用することを願っています:) –

関連する問題