※以下の内容は社内研修での勉強内容を転載したものとなります。
DIとか本を読んでもよく分からなかったので調べました。
DI
DI = Dependency Injection
- 「依存性の注入」とよく訳される。(けどなんだかいまいちよく分からずスッキリしない、、、)
- dependencyを英訳すると*「A dependency is an object that can be used (a service).」*。つまりDIとは、「依存性の注入」じゃなくて、**「オブジェクトの注入」**ということらしい。(こっちの方がなんとなくわかるかも。)
そもそも依存しているとはどのような状態?
- 「クラスAをコンパイルするためには(あるいは正しく動かすためには)、クラスBが既に出来上がってないとだめ」という状態のこと。
- こういう状態にあることを「クラスAはクラスBに依存している」という。
依存性が高いと困ること
- 単体テストがしづらい。
- 依存しているクラスBが壊れるとクラスAも使えないし、どちらに原因があるのか特定しづらい。
- そこで「依存性をクラスの外で定義すればいいんじゃないの?」という発想が生まれてくる。
つまりDI=依存性(オブジェクト)の注入を行うとは?
- クラスAがクラスBに依存しているという情報を、クラスAの外で定義して外からクラスAのインスタンスに突っ込んであげるということ。
- 簡単に言うと「依存性(オブジェクト)を外から注入したい」ということ。
- これが実現されると、クラスBがなくてもクラスAを動かせるようになる。つまり粗結合になり、テストしやすくなる。
参考
・要するに DI って何なのという話
・DI・DIコンテナ、ちゃんと理解出来てる・・?
DIコンテナ
- 単純に言えば、DIを実現するためのフレームワーク(箱、入れ物)。
- DIを自動で行い、インスタンスを組み立ててくれる基盤。
- ただし、DIコンテナがないとDIが実現できないわけではない。
DIを実現するための仕組み
以下のように定義をおこなっていくことでDIが実現される
ApplicationContextとBean定義
- Spring FrameworkではApplicationContextがDIコンテナの役割を担う。
ApplicationContext context = new AnnotationConfigurationContext(AppConfig.class); ①
UserService userService = context.getBean(Userservice.class); ②
①コンフィギュレーションクラスを渡してDIコンテナを生成。
②DIコンテナからUserServiceインスタンスを取得。
- ApplicationContextはBeanFactory(※1)の有する機能以外に以下の機能を有する。
- URL やファイルのようなリソースへのアクセス
- ApplicationListener インタフェースを実装したビーンへのイベントの伝播
- 複数のコンテキストをロード可能
(※1)
・Spring の中でもっとも基本となる重要なパッケージは org.springframework.beans パッケージと org.springframework.context パッケージ。
・Dependency Injection の基本的な機能はこれらのパッケージが提供している。
・これらのパッケージのなかでも JavaBeans を管理する実際のコンテナとして中心的な役割を果たすのが BeanFactory。
・BeanFactory は依存関係が記述された定義ファイルを元に JavaBeans の生成・管理を行う。
- 実装例のAppConfigクラスは、DIコンテナに対する設定ファイル。
- 「Java Config」とも呼ばれる。
- Java Configクラスの実装例についてはp.16~17参照
ApplicationContextを使ったアプリケーションでは
- DiコンテナにConfigurationを使用して、コンポーネントを登録し、ApplicationContextインターフェースを通じてDIコンテナからBeanを取得する。
- DIコンテナに登録するコンポーネントを「Bean」、Configurationのことを「Bean定義」と呼ぶ。
- DIコンテナからBeanを取得することを「ルックアップ」と呼ぶ。
代表的なBean定義(Configuration)
① JavaベースConfiguration
→ @Configurationアノテーションが付与されたJavaクラスに@Beanアノテーションが付与されたメソッドを使用し、Beanを定義する方法。
② XMLベースConfiguration
→ XMLファイル中の要素のclass属性にFQCN(完全修飾クラス名)を記述し、や要素を使ってインジェクションの設定を行う方法。
(内部構造が分かりやすいがエラーがわかりにくい)
③ アノテーションベースConfiguration
→ @Componentなどのまあーカーアノテーションが付与されたクラスを「コンポーネントスキャン」という手段を用いて自動的にDIコンテナに登録する方法。
インジェクションの種類
① セッターインジェクション
→ コンポーネントがセッターを持つ場合、そのセッターの引数に対して依存するコンポーネントを注入する方法。
② コンストラクタインジェクション
→ コンストラクタに依存コンポーネントを直接設定する方法。(javaベース)
→ 要素で参照するコンポーネントを設定する方法。(XMLベース)
→ コンストラクタに@Autowired を付与する方法。(アノテーションベース)
③ フィールドインジェクション
→ インジェクションしたいフィールドに@Autowired を付与する方法。
→ コンストラクタやセッターは不要で省略可。