コントロールの逆転入門とSpringによる依存性注入
{空}[sc name =” spring__start”]
1概要
この記事では、IoC(Inversion of Control)とDI(Dependency Injection)の概念を紹介し、次にこれらがSpringフレームワークでどのように実装されているかを見ていきます。
2コントロールの反転とは何ですか?
制御の反転はソフトウェア工学の原則であり、それによってプログラムのオブジェクトまたは部分の制御がコンテナまたはフレームワークに移される。オブジェクト指向プログラミングのコンテキストで最もよく使用されます。
カスタムコードがライブラリを呼び出す従来のプログラミングとは対照的に、IoCはフレームワークがプログラムのフローを制御してカスタムコードを呼び出すことを可能にします。これを可能にするために、フレームワークは追加のビヘイビアを組み込んだ抽象化を使用します。
このアーキテクチャの利点は次のとおりです。
-
タスクの実行をその実装から切り離す
-
異なる実装間の切り替えを簡単にする
プログラムのより大きなモジュール性
-
コンポーネントを隔離したり、モックすることで、プログラムのテストが非常に簡単になる
その依存関係とコンポーネントが契約を通じて通信できるようにする
制御の反転は、次のようなさまざまなメカニズムを通じて実現できます。
戦略設計パターン、サービスロケーターパターン、ファクトリーパターン、および依存性注入(DI)。
次にDIについて見ていきます。
3依存性注入とは何ですか?
依存性注入は、それを介してIoCを実装するためのパターンです。そこでは、反転されるコントロールはオブジェクトの依存性の設定です。
オブジェクトを他のオブジェクトと接続する、つまりオブジェクトを他のオブジェクトに「注入する」という行為は、オブジェクト自体ではなくアセンブラによって行われます。
伝統的なプログラミングでオブジェクトの依存関係を作成する方法は次のとおりです。
public class Store {
private Item item;
public Store() {
item = new ItemImpl1();
}
}
上記の例では、
Store
クラス自体の中に
Item
インターフェースの実装をインスタンス化する必要があります。
DIを使用することで、必要な
Item
の実装を指定せずに例を書き直すことができます。
public class Store {
private Item item;
public Store(Item item) {
this.item = item;
}
}
次のセクションでは、メタデータを介して
Item
の実装を提供する方法について説明します。
IoCとDIはどちらも単純な概念ですが、システムを構築する方法に深い意味を持つため、十分に理解する価値があります。
4春のIoCコンテナ
IoCコンテナは、IoCを実装するフレームワークに共通の特徴です。
Springフレームワークでは、IoCコンテナは
ApplicationContext
インタフェースによって表されます。 Springコンテナは、
beans
と呼ばれるオブジェクトのインスタンス化、設定、および組み立て、ならびにそれらのライフサイクルの管理を担当します。
Springフレームワークは
ApplicationContext
インターフェースのいくつかの実装を提供します – スタンドアロンアプリケーションのための
ClassPathXmlApplicationContext
と
FileSystemXmlApplicationContext
、そしてWebアプリケーションのための
WebApplicationContext
。
Beanを組み立てるために、コンテナーは構成メタデータを使用します。これはXML構成またはアノテーションの形式にすることができます。
手動でコンテナをインスタンス化する方法は次のとおりです。
ApplicationContext context
= new ClassPathXmlApplicationContext("applicationContext.xml");
上記の例で
item
属性を設定するために、メタデータを使うことができます。
その後、コンテナはこのメタデータを読み取り、実行時にそれを使用してBeanを組み立てます。
Springでの依存性注入は、コンストラクタ、セッター、またはフィールドを通して行うことができます。
5コンストラクタベースの依存性注入
コンストラクタベースの依存性注入
の場合、コンテナはそれぞれ設定したい依存性を表す引数でコンストラクタを呼び出します。
Springは各引数を主に型によって解決し、その後に属性の名前と曖昧さを解消するためのインデックスを続けます。アノテーションを使用して、Beanの構成とその依存関係を見てみましょう。
@Configuration
public class AppConfig {
@Bean
public Item item1() {
return new ItemImpl1();
}
@Bean
public Store store() {
return new Store(item1());
}
}
@ Configuration
アノテーションは、そのクラスがBean定義のソースであることを示します。また、それを複数の構成クラスに追加することもできます。
@ Bean
アノテーションは、Beanを定義するためのメソッドに対して使用されます。カスタム名を指定しないと、Bean名はデフォルトのメソッド名になります。
デフォルトの
singleton
スコープを持つBeanの場合、SpringはまずそのBeanのキャッシュされたインスタンスが既に存在するかどうかを確認し、存在しない場合にのみ新しいインスタンスを作成します。
prototype
スコープを使用している場合、コンテナは各メソッド呼び出しに対して新しいBeanインスタンスを返します。
Beanの構成を作成するもう1つの方法は、XML構成を使用することです。
<bean id="item1" class="org.baeldung.store.ItemImpl1"/>
<bean id="store" class="org.baeldung.store.Store">
<constructor-arg type="ItemImpl1" index="0" name="item" ref="item1"/>
</bean>
6. セッターベースの依存性注入
セッターベースのDIの場合、コンテナーは、引数のないコンストラクターまたは引数のない静的ファクトリーメソッドを呼び出してBeanをインスタンス化した後に、クラスのセッターメソッドを呼び出します。アノテーションを使用してこの設定を作成しましょう:
@Bean
public Store store() {
Store store = new Store();
store.setItem(item1());
return store;
}
XMLを同じ構成のBeanに使用することもできます。
<bean id="store" class="org.baeldung.store.Store">
<property name="item" ref="item1"/>
</bean>
コンストラクタベースとセッターベースのインジェクションタイプは、同じBeanに対して組み合わせることができます。 Springのドキュメントでは、必須の依存関係にはコンストラクタベースのインジェクションを使用し、オプションの依存関係にはセッターベースのインジェクションを使用することを推奨しています。
7. フィールドベース
依存性注入**
フィールドベースのDIの場合、
@ Autowired
アノテーションを付けて依存関係をマークすることで依存関係を注入できます。
public class Store {
@Autowired
private Item item;
}
Store
オブジェクトの構築中に、
Item
Beanを注入するためのコンストラクターまたは設定メソッドがない場合、コンテナーはリフレクションを使用して
Item
を
Store
に注入します。
XML設定
を使用してこれを達成することもできます。
この方法はより単純でよりきれいに見えるかもしれませんが、次のようないくつかの欠点があるため使用することはお勧めできません。
-
このメソッドはリフレクションを使って依存関係を注入します。
コンストラクタベースまたはセッターベースのインジェクションよりもコストがかかる
** これを使って複数の依存関係を追加し続けるのは本当に簡単です
アプローチ。複数の引数を持つコンストラクター注入を使用していた場合、このクラスは単一責任原則に違反する可能性がある複数のことをしていると考えられます。
@ Autowired
アノテーションの詳細は
Wiring In Spring
の記事にあります。
8自動配線の依存関係
Wiring
は、定義されているBeanを調べることによって、Springコンテナが共同作業中のBean間の依存関係を自動的に解決することを可能にします。
XML構成を使用してBeanを自動配線する方法は4つあります。
-
no
:
デフォルト値 – これは自動配線が使用されないことを意味します
豆と依存関係を明示的に命名する必要があります
byName
:** 自動配線はプロパティの名前に基づいて行われます。
そのため、Springはプロパティと同じ名前のBeanを探します。
設定する必要があります
byType
:**
byName
自動配線と同様、タイプのみに基づく
プロパティの。つまり、Springは設定するプロパティと同じ種類のプロパティを持つBeanを探します。そのタイプのBeanが複数ある場合、フレームワークは例外をスローします。
-
constructor
:
自動配線はコンストラクタ引数に基づいて行われます。
Springがコンストラクタの引数と同じ型のBeanを探すという意味
たとえば、上記で定義した
item1
Beanを
store
Beanにタイプ別に自動配線しましょう。
@Bean(autowire = Autowire.BY__TYPE)
public class Store {
private Item item;
public setItem(Item item){
this.item = item;
}
}
タイプ別の自動配線に
@ Autowired
アノテーションを使用してBeanを注入することもできます。
public class Store {
@Autowired
private Item item;
}
同じタイプのBeanが複数ある場合は、
@ Qualifier
アノテーションを使用してBeanを名前で参照できます。
public class Store {
@Autowired
@Qualifier("item1")
private Item item;
}
それでは、XML設定を通じてタイプ別にBeanを自動配線しましょう。
<bean id="store" class="org.baeldung.store.Store" autowire="byType"> </bean>
次に、
item
という名前のBeanを、XMLを介して
store
beanの
item
プロパティにインジェクトします。
<bean id="item" class="org.baeldung.store.ItemImpl1"/>
<bean id="store" class="org.baeldung.store.Store" autowire="byName">
</bean>
コンストラクタの引数や設定メソッドを使って依存関係を明示的に定義することで、自動配線を上書きすることもできます。
9遅延初期化ビーンズ
デフォルトでは、コンテナは初期化中にすべてのシングルトンBeanを作成および設定します。これを回避するには、Bean設定で
lazy-init
属性を値
true
とともに使用します。
<bean id="item1" class="org.baeldung.store.ItemImpl1" lazy-init="true"/>
その結果、
item1
Beanは最初の要求時にのみ初期化され、起動時には初期化されません。これの利点は初期化時間が速いことですが、トレードオフはコンフィグレーションエラーがBeanが要求された後にしか発見されないことであり、それはアプリケーションが既に実行されてから数時間または数日である可能性があります。
10結論
この記事では、制御の反転と依存性注入の概念を紹介し、それらをSpringフレームワークで例示しました。
Martin Fowlerの記事でこれらの概念についてもっと読むことができます。
コントロール]**
コントロールの反転
コンテナと依存性注入パターン]。
そして、SpringのIoCとDIの実装についての詳細はhttp://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-dependencies[Spring Framework Reference Documentation]をご覧ください。