Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発という書籍を読んでいて、重要だと思う箇所をまとめました。(独自に少し補完しました。)
あとで見返せるように参考書籍のページ数を記載しています。
今回は、DIについての記事になります。
インジェクションの種類
SpringでDIには以下の3種類が存在する。(P.23)
* セッターインジェクション
* コンストラクタインジェクション
* フィールドインジェクション
セッターインジェクション
セッターの引数に対してDIする方法。
メリット :既存のSetterを生かしたままDIを行うことが出来る。
デメリット:フィールドインジェクションに比べて面倒くさい。
@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修飾子を付けて不変に出来る。
デメリット:フィールドインジェクションに比べて面倒くさい。
@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を行うことが前提のコードになってしまう。
@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 (デフォルト) |
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つのフェーズのうち、ほとんどの時間は利用フェーズになる。
初期化フェーズ
- Bean読み込み → Beanを生成する準備。
- 依存性の解決 → Beanインスタンスの生成および、インジェクション実施。
- Post Construct → インスタンス生成後の処理。インジェクションしたBeanを利用することが出来る。
@Component
public class UserServiceImpl implements UserService {
@PostConstruct
void pupulateCache() {
// キャッシュ生成処理
}
}
終了フェーズ
終了フェーズでは、「Pre Destroy」と呼ばれる破棄前処理が行われる。(P.50)
@Component
public class UserServiceImpl implements UserService {
@PreDestroy
void clearCache() {
// キャッシュ破棄処理
}
}
参考元
サイト
アノテーションによるDIの実装(2/5):初心者のためのSpring Framework入門
Spring MVCのコントローラでの戻り値いろいろ - Qiita
Springで例外ハンドリング - Qiita
エンジニアの暇潰し : Spring+JSFでManagedBeanをSpring管理にする