Springフレームワーク06:DI
【ふわっとざっくり。DIとは】
◆インスタンス管理
@Autowired アノテーションをフィールドに付けると、DIコンテナから インスタンスを取得する。
◆DIコンテナ・・・インスタンスをためておく領域
(要求をした時にインスタンスを返す)
①インスタンスの生成
毎回 new したインスタンスをアプリケーションに渡すのか、それとも一度new したインスタンスをアプリケーションに渡すのかを管理する
(リクエストが複数回来るなら毎度newするが、1つのインスタンスを利用できる場合もあるため)
②インスタンスのライフサイクル管理
サーブレットのリクエストスコープやセッションスコープに、 インスタンスを簡単に登録できる
インスタンスの破棄を実施する
(アプリケーション側で クラスを new したり、利用が済んだ変数に null を入れる必要がなくなるため、コードの可読性が上がる)
【DI(Dependency Injection)の要素】
◆「依存性」
・他のクラスをローカル変数として持っている
・他のクラスがメソッドの引数、戻り値になっている
→平たく言うと、他のクラスを利用しているかどうか
クラス間の依存度が高い状態を「密結合」と言う
→簡単にパーツの切り替えができず、変更に弱いアプリケーションになる
インタフェースを使うと依存度合いを下げることができる
依存度が低い状態のことを「疎結合」と言う
→変更に強いアプリケーションになる
※ Springでは、この考えが重要!
◆「注入」
・インターフェース型の変数に、インスタンスを入れることを注入と言う
多数のインスタンスを生成する場合、new するコードが増えれば増えるほど、変更があった際の修正量が多くなる
インスタンスを生成するFactoryクラスを用意する
メソッドを static にすることで、Factoryクラスを生成しなくても呼び出せる
(呼び出し元にインスタンスを返す)
public class EngineFactory {
public static Engine createHondaEngine() {
return new HondaEngineVer 2();
}
public static Engine createHondaEngine() {
return new NissanEngine();
}
}
次に、Factoryクラスを使ってインスタンスを取得する形に main を修正する
new するクラスが変わった場合、メソッドの中身を変えるだけで済む
public class Main {
public static void main( String[] args) {
Engine hondaEngine1 = EngineFactory.createHondaEngine();
Engine hondaEngine2 = EngineFactory.createHondaEngine();
Engine nissanEngine1 = EngineFactory.createHondaEngine();
Car car1 = new Car(hondaEngine1);
Car car2 = new Car(hondaEngine2);
Car car3 = new Car(nissanEngine1);
}
}
以上をふまえまして…
【DI(Dependency Injection)】
DI は「依存性」と「注入」を同時に、しかも簡単に実行してくれる
◆内部の処理
コンポーネントスキャン(DIの管理対象のクラスを探す)
Springを起動すると、コンポーネントスキャンという処理が走ります。
DIで管理する対象のアノテーションが付けられているクラスを探す
※ コンポーネントスキャン対象のアノテーション
@Component
@Controller
@Service
@Repository
@Configuration
@RestController
@ControllAdvice
@ManagedBean
@Named
これらのアノテーションが付いているクラスが、DIの管理対象とみなされる
中でも、よく使うアノテーションは
@Component
@Controller
@Service
@Repository
DIコンテナ上で管理するクラスのことを「Bean(ビーン)」と呼ぶ
◆インスタンスの生成と注入
DI対象のクラス(Bean)を集めた後、各インスタンスを DIが生成(new)する その後、生成したインスタンスを@Autowiredアノテーションが付いているフィールドなどに注入(代入)する
public class DependencyInjection {
// 各クラスのインスタンスを生成
private SampleComponent component = new SampleComponent();
private SampleService service = new SampleService();
// SampleComponentインスタンスのgetter
public static SampleComponent getSampleComponent() {
return component;
}
// SampleServiceインスタンスのgetter
public static SampleService getSampleService() {
return service;
}
}
※ 毎回newはしていない。
→その都度Factoryクラスを作る手間が省ける
◆@Autowiredを付けられる箇所
・フィールド変数
・コンストラクタの引数
・setterの引数
【まとめ】
DIコンテナの機能とは、クラスのインスタンスを生成して、注入(変数に代入)することを意味する
【DIのライフサイクル管理機能】
インスタンスの生成(new)と破棄(ガベージコレクションの対象にする)を管理する
Springでは、ライフサイクル管理をする場合、@Scopeアノテーションを付けた上で、 どのスコープに登録するかを指定する
@Component
@Scope("prototype")
public class SampleComponent {
}