Spring Framework 要点まとめ ～ DIについて

[Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発](https://www.amazon.co.jp/Spring徹底入門-Spring-FrameworkによるJavaアプリケーション開発-株式会社NTTデータ/dp/4798142476/)という書籍を読んでいて、重要だと思う箇所をまとめました。（独自に少し補完しました。）
あとで見返せるように参考書籍のページ数を記載しています。

今回は、DIについての記事になります。

# インジェクションの種類
SpringでDIには以下の3種類が存在する。(P.23)
* セッターインジェクション
* コンストラクタインジェクション
* フィールドインジェクション

## セッターインジェクション
セッターの引数に対してDIする方法。

メリット　：既存のSetterを生かしたままDIを行うことが出来る。
デメリット：フィールドインジェクションに比べて面倒くさい。

```java
@Component
public class UserServiceImpl implements UserService {
    private UserRepository userRepository;
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }
}
```

## コンストラクタインジェクション
コンストラクタの引数に対してDIする方法。

メリット　：フィールドにfinal修飾子を付けて不変に出来る。
デメリット：フィールドインジェクションに比べて面倒くさい。

```java
@Component
public class UserServiceImpl implements UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    
    @ConstructorProperties({"userRepository", "passwordEncoder"})
    public UserServiceImpl(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }
}
```

## フィールドインジェクション
クラスのフィールドに対してDIする方法。

メリット　：コード量が少なくて一番シンプルに書ける。
デメリット：DIを行うことが前提のコードになってしまう。

```java
@Component
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private PasswordEncoder passwordEncoder;
}
```

# コンポーネントスキャンの対象
コンポーネントスキャンとは、クラスローダーをスキャンして特定のクラスを自動的にDIコンテナに登録すること。(P.35)

デフォルトでは、以下のアノテーションが付いたクラスが対象となる。

|アノテーション|説明|
|:----|:----|
|@Controller|MVCパターンのCの役割を担うコンポーネント。このアノテーションを付与したコンポーネントでは、クライアントからのリクエスト／レスポンスに関わる処理をする。|
|@Service|ビジネスロジックを実装するコンポーネントであることを表すアノテーション。|
|@Repository|データの永続化に関わる処理を提供するコンポーネント。ORMなどを利用して、データのCRUD処理を実装する。|
|@Component|上記3つに当てはまらないコンポーネント。ユーティリティクラスなどに付与する。|
|@Configuration|クラス宣言の前に記述します。このアノテーションは、このクラスがBeanの設定を行うものであることを示します。Bean設定クラスには常にこれをつけます。|
|@RestController|JSONやXML等を返すWebAPI用のコントローラに付与する。|
|@ControllerAdvice|Controllerを横断して例外をハンドリングする場合、例外ハンドリング用のクラスにこのアノテーションを付与する。ExceptionHandler系のクラスに使用。|
|@ManagedBean|本来はJSFが管理してるManagedBeanを表すもの。Springの@Componentを付けた時と同じ意味になると思われる。|
|@Named|本来はJava(EE)系でのインジェクション対象を表すもの。Springの@Componentを付けた時と同じ意味になると思われる。|

# Beanのスコープ
Springでは、DIコンテナに登録するコンポーネントのことを**「Bean」**、Configurationのことを「Bean定義」という。
DIコンテナからBeanを取得することを「ルックアップ」という。(P.17)

## Spring Frameworkで利用可能なスコープ
Springで利用可能なスコープ指定の一覧です。(P.39)

|スコープ|説明|
|:----|:----|
|singleton<br/>**(デフォルト)**|DIコンテナの起動時にBeanのインスタンスを生成し、同一のインスタンスを共有して利用する。スコープを設定しない場合はsingletonとして扱われる。|
|prototype|Beanの取得時に毎回インスタンスを生成する。スレッドアンセーフなBeanの場合、singletonスコープを利用できないためprototypeを利用する。|
|session|HTTPのセッション単位でBeanのインスタンスを生成する。Webアプリケーションの場合のみ有効。|
|request|HTTPのリクエスト単位でBeanのインスタンスを生成する。Webアプリケーションの場合のみ有効。|
|globalSession|ポートレット環境におけるGlobalSessionの単位でインスタンスを生成する。ポートレットに対応したWebアプリケーションの場合のみ有効。|
|application|サーブレットのコンテキスト単位でBeanのインスタンスを生成する。Webアプリケーションの場合のみ有効。|
|カスタムスコープ(独自の命名)|独自に定義したルールでBeanのインスタンスを生成する。|

同じクラスの中で、異なるスコープのインジェクションを行う場合は注意が必要。(P.41)

ポートレットに対応したWebアプリケーションとは、"ポートレット Web"なんかで画像検索するとどういうサイトなのかイメージできると思います。

# Beanのライフサイクル
DIコンテナで管理されているBeanのライフサイクルは、次の3つのフェーズで構成されます。(P.47)

* 初期化フェーズ
* 利用フェーズ
* 終了フェーズ

上記3つのフェーズのうち、ほとんどの時間は利用フェーズになる。

## 初期化フェーズ
1. Bean読み込み → Beanを生成する準備。
2. 依存性の解決 → Beanインスタンスの生成および、インジェクション実施。
3. Post Construct → インスタンス生成後の処理。インジェクションしたBeanを利用することが出来る。

```java
@Component
public class UserServiceImpl implements UserService {
    @PostConstruct
    void pupulateCache() {
        // キャッシュ生成処理
    }
}
```

## 終了フェーズ
終了フェーズでは、「Pre Destroy」と呼ばれる破棄前処理が行われる。(P.50)

```java
@Component
public class UserServiceImpl implements UserService {
    @PreDestroy
    void clearCache() {
        // キャッシュ破棄処理
    }
}
```

# 参考元
## サイト
[アノテーションによるDIの実装(2/5):初心者のためのSpring Framework入門](http://libro.tuyano.com/index3?id=7606003&page=2)
[Spring MVCのコントローラでの戻り値いろいろ - Qiita](http://qiita.com/tag1216/items/3680b92cf96eb5a170f0)
[Springで例外ハンドリング - Qiita](http://qiita.com/NagaokaKenichi/items/2f199134a881a776b717)
[エンジニアの暇潰し : Spring+JSFでManagedBeanをSpring管理にする](http://blog.livedoor.jp/crimson373/archives/3074558.html)

## 書籍
[Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発](https://www.amazon.co.jp/Spring徹底入門-Spring-FrameworkによるJavaアプリケーション開発-株式会社NTTデータ/dp/4798142476/)