概要
SpringBootではDIという概念がありますが、「いちいちnewしなくて済む!」という理解しかなく…改めて調べて得た内容をここにまとめます。
DIとは
DIとは「Dependency Injection」の略で、「依存性の注入」と訳されます。
DIはソフトウエア開発のデザインパターンの1つで、DIを用いることで、コンポーネントを構成するインスタンスの生成と依存関係の解決をソースコードから分離することができます。あるクラスAのaメソッドで、あるクラスBをnewして使用している場合、クラスAのaメソッドはクラスBに依存している、と言えます。
依存しているとどんなよくないことが起きるか 例
結合度の高いクラスになる
aメソッドはクラスBに依存しているため、例えばクラスBの実装が完了していないと、部分的に差し替えたりと効率が悪くなります。
テストがしにくい
aメソッドのテストをしようとしても、クラスBの実装を考慮してテストをしなければならなかったり、都度インスタンス化する必要があるなど、テスト観点上都合が悪いです。
メモリの利用効率が悪い
aメソッドが呼ばれるたびにクラスBがnewされているので、都度メモリを消費し、効率が悪いです。
DIコンテナ
上記を解決するのが、SpringBootでいうところのDIコンテナになります。
SpringではDIコンテナというところでインスタンスの管理を行います。
このDIコンテナで管理されるコンポーネントをBeanと呼びます。
クラスをBeanとして定義することで、DIコンテナに管理させます。
Bean定義する場合、クラスに下記アノテーション(ステレオタイプアノテーション)を付与します。
アノテーション | 説明 |
---|---|
@Controller | Spring MVCと連携ができる。コントローラークラスに付与。 |
@Service | 業務ロジッククラスに付与 |
@Repository | データアクセスクラスに付与 |
@Component | 上記に該当しないクラス |
注入
上記でBean登録したクラスを使用したい(注入)場合、@Autowired をクラスAに記載することで、依存性の注入ができる。
@Autowired でインスタンスを生成しているのではなく、DIコンテナにあるBeanを渡してもらってる(注入)しています。
注意点
なんでもかんでもDIコンテナに登録して注入させるようにすればいい、ということではありません。
注意すべきは、Beanはデフォルトだとシングルトンになるため、複数のスレッドで1つの同じインスタンスを共有している状態になります。
なので、インスタンス変数を持っているクラスをDIした場合、注入先で利用されるたびにインスタンス変数が変わりうるためスレッドセーフになっていません。
なので、EntityやDTOなど値を保持するクラスなどはDIしない方がよいです。
インスタンス変数と違って、ローカル変数(メソッド内で使用している変数)の場合はスレッドセーフになります。
参考文献