見出し画像

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 {
}

もしも気に入ったら、サポートお願いします! おやつを買いますので、餌付けができます。