java アノテーション CDI でセッターインジェクション上でコンストラクタを使用する理由




springboot コンストラクタインジェクション (2)

CDIを使用するとき 、コンストラクターまたはセッターインジェクションを使用する理由はまったくありません。 質問で述べたように、コンストラクタで行わなければならないことに@PostConstructメソッドを追加します。

ユニットテストでフィールドを注入するにはReflectionを使う必要があると言う人もいるかもしれませんが、そうではありません。 モックライブラリや他のテストツールはあなたのためにそれを行います。

最後に、コンストラクタインジェクションはフィールドがfinalであることを可能にします、しかしこれは@Injectアノテートされたフィールド(それはfinalあることができない)の本当に不利ではありません。 アノテーションの存在は、フィールドを明示的に設定するコードが存在しないことと相まって、それがコンテナ(またはテストツール)によってのみ設定されることを明確にするはずです。 実際には、注入されたフィールドを再割り当てする人はいません。

コンストラクタとセッターのインジェクションは、開発者が通常手動でインスタンス化し、テストされたオブジェクトに依存関係をインジェクトしなければならなかった時代には意味がありました。 今日では、技術は進化しており、フィールドインジェクションはより良い選択肢です。

私はSOについてここで合理的な答えを見つけることができなかったので、それが重複していないことを願っています。 それでは、なぜ単純なものよりセッターまたはコンストラクターによる注入を好むべきなのか

@Inject
MyBean bean;

あなたがクラス初期化中に注入されたbeanで何かをする必要があるなら、私はコンストラクタ注入の使用法を得ます

public void MyBean(@Inject OtherBean bean) {
    doSomeInit(bean);
    //I don't need to use @PostConstruct now
}

それでも、 @PostConstructメソッドとほぼ同じで、セッターインジェクションはまったく得られません@PostConstructや他のDIフレームワークの@PostConstructではないでしょうか。


Answer #1

コンストラクタとプロパティインジェクションは、CDI以外の環境でも簡単にオブジェクトを初期化するオプションを提供します。

非CDI環境でも、コンストラクタargを渡すだけでオブジェクトを簡単に使用できます。

OtherBean b = ....;
new MyBean(b);

フィールドインジェクションを使用するだけの場合は、フィールドにアクセスするには通常リフレクションを使用する必要があります。フィールドは通常プライベートなのでです。

プロパティインジェクションを使用する場合は、セッターにコードを書くこともできます。 たとえば、検証コードや、セッターが変更したプロパティから派生した値を保持している内部キャッシュをクリアします。 何をしたいのかは、実装のニーズによって異なります。

セッターvsコンストラクターインジェクション

オブジェクト指向プログラミングでは、オブジェクトは構築後に有効な状態になければならず、すべてのメソッド呼び出しはその状態を別の有効な状態に変更します。

セッターインジェクションの場合、セッターがまだ呼び出されていなくても、オブジェクトは構築後に有効な状態になるはずなので、より複雑なステート処理が必要になる可能性があります。 したがって、プロパティが設定されていなくても、オブジェクトは有効な状態でなければなりません。 たとえば、デフォルト値またはnullオブジェクトを使用することによって。

オブジェクトの存在とプロパティの間に依存関係がある場合は、そのプロパティをコンストラクタの引数にする必要があります。 コンストラクタパラメータを使用する場合は依存関係が必要であることを文書化しているので、これによってコードがよりクリーンになります。

だからこのようなクラスを書く代わりに

public class CustomerDaoImpl implements CustomerDao {

  private DataSource dataSource;

  public Customer findById(String id){
     checkDataSource();

     Connection con = dataSource.getConnection();
     ...
     return customer;
  }

  private void checkDataSource(){
     if(this.dataSource == null){
         throw new IllegalStateException("dataSource is not set");
     }
  }


  public void setDataSource(DataSource dataSource){
     this.dataSource = dataSource;
  }

}

どちらかコンストラクタインジェクションを使うべきです

public class CustomerDaoImpl implements CustomerDao {

  private DataSource dataSource;

  public CustomerDaoImpl(DataSource dataSource){
      if(dataSource == null){
        throw new IllegalArgumentException("Parameter dataSource must not be null");
     }
     this.dataSource = dataSource;
  }

  public Customer findById(String id) {    
      Customer customer = null;
     // We can be sure that the dataSource is not null
     Connection con = dataSource.getConnection();
     ...
     return customer;
  }
}

私の結論

  • オプションの依存関係ごとにプロパティを使用します
  • すべての必須の依存関係に コンストラクター引数を使用してください。

PS:私のブログpojosとjava beanの違いは、私の結論をさらに詳しく説明しています。





cdi