Spring MVC
およびPortlets
に関するいくつかの投稿で、フィールドインジェクションは推奨されていません。原因を取得しようとしているので、フィールドインジェクションを使用しているかどうかを自問しましたが、答えられません。 フィールドインジェクションは、次のように@Autowired
を使用してBean
を属性にインジェクトする場合です。
CartController.Java:
...
@Autowired
private Cart cart;
...
BookshopConfiguartion.Java:
@Configuration
public class BookShopConfiguration {
@Bean
public Cart cart(){
return new Cart();
}
//more configuration
Cart.Java
は、カート内の本に関する情報を保存および提供するために使用されます。
私の研究中にconstructor injectionについて読みました。
MyComponent.Java:
...
public class MyComponent{
private Cart cart;
@Autowired
public MyComponent(Cart cart){
this.cart = cart;
}
...
これら両方のタイプの注入の長所と短所は何ですか?
EDIT 1:この質問は この質問 の重複としてマークされているので、チェックしました。質問にも回答にもコード例がないため、使用している注入タイプを推測して正しいかどうかはわかりません。
注入タイプ
Beanに依存関係を注入する方法には、次の3つのオプションがあります。
オプション3を使用しています。フィールドで@Autowired
を直接使用すると、これが発生します。
注入ガイドライン
一般的なガイドライン Springが推奨 ( Constructor-based DI または Setter-based DI のセクションを参照)は次のとおりです。
フィールドインジェクションの欠点
フィールドインジェクションが嫌われる理由は次のとおりです。
結論
ニーズに応じて、主にコンストラクターインジェクションまたはコンストラクターとセッターインジェクションの組み合わせを使用する必要があります。フィールドインジェクションには多くの欠点があり、避けるべきです。フィールドインジェクションの唯一の利点は、書くのがより便利であることです。これは、すべての短所を上回っていません。
さらに読む
フィールドインジェクションが通常推奨されない理由についてブログ記事を書きました: フィールド依存性インジェクションは有害と考えられます 。
これはソフトウェア開発における終わりのない議論の1つですが、業界の主要なインフルエンサーはこのトピックについてより多くの意見を持ち、より良いオプションとしてコンストラクター注入を提案し始めています。
コンストラクターインジェクション
長所:
短所:
基本的に、フィールド注入は反対です。
味の問題。それはあなたの決断です。
しかし、なぜコンストラクターインジェクションを使用しないのか説明できます.
@Service
、@Repository
、@Controller
のすべてのBeanにコンストラクターを実装したくありません。つまり、約40〜50個以上のBeanがあります。新しいフィールドを追加するたびに、コンストラクターを拡張する必要があります。いいえ。私はそれを望んでいませんし、する必要もありません。
Bean(サービスまたはコントローラー)に多くの他のBeanを注入する必要がある場合はどうなりますか? 8つのパラメーターを持つコンストラクターは非常にいです。
CDIを使用している場合、コンストラクタは気にしません。
EDIT:Vojtech Ruzicka氏:
クラスの依存関係が多すぎて、おそらく単一の責任原則に違反しているため、リファクタリングする必要があります
はい。理論と現実。次に例を示します:DashboardController
は単一パス*:8080/dashboard
にマップされます。
私のDashboardController
は、他のサービスから多くの情報を収集して、ダッシュボード/システム概要ページに表示します。この単一のコントローラーが必要です。したがって、この1つのパス(基本認証またはユーザーロールフィルター)のみを保護する必要があります。
Field
@Autowired
private DependencyA dependencyA;
@Autowired
private DependencyB dependencyB;
@Autowired
private DependencyC dependencyC;
何が問題なのですか?ご覧のとおり、Fieldバリアントは非常に見栄えが良いです。非常に短く、簡潔で、定型的なコードはありません。コードは読みやすく、ナビゲートしやすいです。あなたのクラスは重要なことに集中することができ、DIボイラープレートによって汚染されません。 @Autowiredアノテーションをフィールドの上に置くだけで、それで終わりです。依存関係を提供するためのDIコンテナー専用の特別なコンストラクターまたはセッターはありません。 Javaは非常に冗長なので、コードを短くするあらゆる機会を歓迎しますか?
単一責任原則違反
新しい依存関係を追加するのは非常に簡単です。たぶん簡単です。 6、10、または数十の依存関係を追加しても問題ありません。 DIのコンストラクターを使用している場合、特定のポイントの後、コンストラクターのパラメーターの数が非常に多くなり、何かが間違っていることがすぐにわかります。通常、依存関係が多すぎるということは、クラスの責任が多すぎることを意味します。これは、単一責任原則および懸念の分離に違反する可能性があり、クラスがさらなる検査と可能なリファクタリングを必要とすることを示す良い指標です。このアプローチは無期限にスケーリングできるため、フィールドに直接注入する場合、このようなレッドフラグはありません。
依存関係の非表示
DIコンテナを使用すると、クラスが独自の依存関係を管理する必要がなくなります。依存関係を取得する責任は、クラスから抽出されます。現在、他の誰かが依存関係を提供する責任があります-DIコンテナー、またはテストでそれらを手動で割り当てます。クラスがその依存関係を取得する責任を負わなくなった場合、パブリックインターフェイス(メソッドまたはコンストラクター)を使用してそれらを明確に通信する必要があります。このようにして、クラスに必要なものが明確になり、オプション(セッター)か必須(コンストラクター)かが明確になります。
DIコンテナカップリング
DIフレームワークの中心的なアイデアの1つは、マネージクラスが使用されるDIコンテナに依存しないことです。言い換えれば、必要な依存関係をすべて渡せば、独立してインスタンス化できる単純なPOJOである必要があります。この方法により、DIコンテナーを開始せずに単体テストでインスタンス化し、個別にテストできます(より統合テストに近いコンテナーで)。コンテナカップリングがない場合、クラスを管理対象または非管理対象として使用するか、新しいDIフレームワークに切り替えることさえできます。
ただし、フィールドに直接注入する場合、必要なすべての依存関係でクラスをインスタンス化する直接的な方法は提供しません。つまり:
必須のコラボレーターが不足しており、使用するとNullPointerException
になる場合に、状態でnewを使用してオブジェクトを作成する方法があります(デフォルトコンストラクターを呼び出す)。そのようなクラスは、リフレクション以外に必要な依存関係を提供する方法がないため、DIコンテナ(テスト、他のモジュール)の外部では再利用できません。不変性コンストラクターとは異なり、フィールドインジェクションを使用して最終フィールドに依存関係を割り当て、オブジェクトを効果的に可変にすることはできません。