Spring Boot入門① ～DI～

Springの学習を進めるに当たって、教材やネットで調べた情報を自分なりにまとめます。
私はフレームワークの経験無に近い人間なので、超入門的な内容になります。

## 始める前に

先に、「Spring Boot」とは何なのか。
「Spring Framework」の規模がどんどん膨大になって来て、どう使えば良いか分かり辛くなりました。
そこで登場したのが「Spring Boot」です。

- 複雑なXML設定ファイルが要らない
- TomcatなどのWebコンテナを内含する

のような特徴を活かし、Springベースのアプリケーションを手っ取り早く作成、実行できるようにしたフレームワークです。
「Spring Framework」を使って簡単にアプリケーションを作れるようにしたもの、と理解してください。

では、これからSpringアプリケーションを作るのに必要な知識を1つずつ身に付けて行きます。


## DI（Dependency Injection）

DIは日本語で言うと「依存性の注入」になります。
意味的には「オブジェクトの注入」と理解すれば良いです。
クラスの外から依存性（オブジェクト）を注入してあげることで、クラス間の依存関係を解決するといった目的を持ちます。

### DIコンテナ

DIを実現するためのフレームワークです。
DIコンテナを経由してインスタンスを生成、管理します。
クラスの依存関係を解決する以外にも、以下のような副次効果を得られます。

・インスタンスのスコープ制御が出来る。
　→毎回生成するか、シングルトンにするかなど
・インスタンスのライフサイクルをイベント制御できる。
　→生成時、破棄時のイベント処理など
・共通処理を埋め込むことができる。
・オブジェクト同士が疎結合になるため、テストがしやすくなる。


### Bean定義

DIコンテナがインスタンスを管理するための設定ファイルを定義します。
設定方法は3つあります。

- XML
- JavaConfig
- アノテーション

今回はアノテーションでの設定を見ていきます。

### アノテーション

JAVAのソースにアノテーションを付与することでBean定義を行っていきます。
重要なアノテーションは

@Component
@ComponentScan
@Autowired

になります。

#### ComponentScan

Componentアノテーションを付けたクラスをDIコンテナに登録してくれるアノテーションです。
ComponentScanアノテーションを付けたクラスと同じパッケージ以下のクラスをスキャンしてDIコンテナに登録します。

```SpringSampleApplication.java
//@SpringBootApplication
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class SpringSampleApplication {

	public static void main(String[] args) {
		ConfigurableApplicationContext context = SpringApplication.run(SpringSampleApplication.class, args);
		SampleB sampleb = context.getBean(SampleB.class);
		sampleb.testDi();
	}
}
```

@SpringBootApplicationは@Configuration、@EnableAutoConfiguration、@ComponentScanを実行しています。
サンプルコードではあえて分けてアノテーションを付与しています。

#### Component

注入するクラスに付けます。
クラスに対してComponentアノテーションを付けると、そのクラスをDIコンテナが管理してくれるようになります。

```SampleA.java
@Component
public class SampleA {
		
	public String getClassName() {
		return this.getClass().getName();
	}
}
```

自身のクラス名を返すのみのコンポーネントです。

#### Autowired

注入されるフィールドに付けます。
DIコンテナはAutowiredアノテーションを付けたフィールドに対して、合致するオブジェクトを探してインジェクションします。

```SampleB.java
@Component
public class SampleB {

	@Autowired
	private SampleA sampleA;
	
	public void testDi() {
		System.out.println("called " + sampleA.getClassName());
	}
}
```

DIコンテナからsampleAインスタンスを注入してもらいます。
これでsampleAのクラス名を取得することができます。

SampleBもmainメソッドで呼び出す必要があるため、コンポーネントとして登録しています。

### 注意点

以下のケースはDIできないようです。

・staticにDI
・new生成したインスタンスでのDI

今回、mainメソッドで実行しているため、

```SpringSampleApplication.java
@Autowired
private static SampleB sampleb;
/* 省略 */
sampleb.testDi();
```

だったり

```SpringSampleApplication.java
SampleB sampleb = new SampleB();
sampleb.testDi();
```

を試してみたんですが、両方ともうまくDIされずNullPointerExceptionが発生しました。

### 備考

Component以外にもスキャンの対象になるアノテーションがいくつか存在します。
クラスの役割に応じて各アノテーションを使い分けるようにしましょう。

@Controller（@RestController）
　→MVCのControllerを対象とする
@Service
　→ビジネスロジック等のサービス層を対象とする
@Repository
　→DAOなどDBアクセスを行うクラスを対象とする



## 参考資料
[はじめてのSpring Boot](https://www.amazon.co.jp/%E3%81%AF%E3%81%98%E3%82%81%E3%81%A6%E3%81%AESpring-Boot%E2%80%95%E3%80%8CSpring-Framework%E3%80%8D%E3%81%A7%E7%B0%A1%E5%8D%98Java%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA-I%E3%83%BB-BOOKS/dp/4777518655)
[springの再入門 - DI（依存性注入）](https://qiita.com/park-jh/items/4df5c67d895b2ea219d6)
[DI・DIコンテナ、ちゃんと理解出来てる・・？](https://qiita.com/ritukiii/items/de30b2d944109521298f)