このシリーズでは、Spring Bootで誰もが一度はつまずきやすいポイントを、Javaの経験が浅い方でも無理なく理解できるように、できるだけ難しい言葉を使わずに解説していきます。
今回は第2章「DIの基本編」です。Spring Bootで開発するうえで必ず押さえておきたい「依存性注入(DI)」の仕組みを、イメージで理解していきましょう。
DIとは?

まず「DI」という言葉の意味から確認していきましょう。
DIとは、Dependency Injection の頭文字を取った言葉です。「Dependency」は「依存性」、「Injection」は「注入」を意味します。そのため、日本語では「依存性注入」と呼ばれています。
ただ、「依存性を注入する」と聞いても、まだイメージしにくいのではないでしょうか。
そこで次は、コントローラクラスとサービスクラスを例に、DIの前提となる「依存関係」について見ていきましょう。
依存関係のイメージ

コントローラクラスとサービスクラスの関係を見てみましょう。
図の見方は次のとおりです。
- 左側にはコントローラクラスの
MainControllerがあります - 右側にはサービスクラスの
MainServiceがあります MainControllerのmainMethodでは、MainServiceのserviceMethodを呼び出しています
つまり、MainController は MainService がなければ必要な処理を完了できません。
このように、あるクラスが別のクラスを必要としている状態を「依存関係」と呼びます。今回の例では、MainController が MainService に依存しています。
それでは、Springは MainService をどのように準備するのでしょうか。次で見ていきましょう。
インスタンス化と内部メモリへの格納

続いて、インスタンス化と、コンテナへの格納について見ていきます。
Spring Bootが起動すると、Springフレームワークは MainController と MainService をインスタンス化します。インスタンス化とは、クラスから実際に使用できるオブジェクトを生成することです。
そして、生成した2つのインスタンスを、内部メモリ上にあるコンテナへ格納します。このコンテナに格納されたインスタンスは、Springによって管理されます。
これで、依存性注入を行うための準備が整いました。
内部メモリから依存性注入まで

コンテナには、MainController と MainService の2つのインスタンスが格納されています。
次にSpringは、MainController が MainService を必要としていることを確認します。依存関係が確認できると、コンテナで管理している MainService を MainController へ注入します。
これによって、MainController の mainMethod から、MainService の処理を呼び出せるようになります。
このように、Springが必要なクラスを注入する仕組みを「DI」、日本語では「依存性注入」と呼びます。
DIされるまでの流れ

ここまでの流れを整理します。
- インスタンス化:Spring Bootの起動直後に、対象となるクラスをインスタンス化する
- 内部メモリへ格納:生成したインスタンスを、内部メモリ上のコンテナへ格納する
- 依存関係を確認:どのクラスが、どのクラスを必要としているのかをSpringが確認する
- 注入(DI):必要なクラスを、依存しているクラスへ注入する
この4つの流れによって、Springの依存性注入が行われます。
次は、この仕組みが実際のコードでどのように表現されるのかを見ていきましょう。
DIのコード例

依存性注入(DI)のコード例を見ていきましょう。
まず、コントローラクラスの MainController です。mainMethod では、MainService の serviceMethod を呼び出しています。
@RestController
class MainController {
@Autowired
MainService mainService;
@GetMapping("/main")
String mainMethod() {
return mainService.serviceMethod();
}
}
次に、サービスクラスの MainService です。serviceMethod は「Hello World」という文字列を返します。
@Service
class MainService {
String serviceMethod() {
return "Hello World";
}
}
それでは、この2つのクラスでDIを行うためのアノテーションを見ていきましょう。
MainControllerには@RestControllerを、MainServiceには@Serviceを付けています。これらのアノテーションは、対象のクラスをSpringに認識してもらうための目印です。Springはこの目印が付いたクラスをインスタンス化し、コンテナに格納しますMainControllerでは、MainServiceのフィールドに@Autowiredを付けています。@Autowiredは、コンテナに格納されているMainServiceをここへ注入してほしいという指示です
これによって、Springが MainService を MainController へ注入します。MainService が注入されると、mainMethod から serviceMethod を呼び出せるようになります。
このように、@RestController と @Service を目印にSpringがコンテナへ格納し、@Autowired で必要なクラスを注入します。
コンテナへの格納に使う主なアノテーション

最後に、Springのコンテナへの格納に使われる、主なアノテーションを紹介します。
| アノテーション | 使い方 |
|---|---|
@Controller / @RestController | クラスに付ける |
@Service | クラスに付ける |
@Repository | クラスに付ける |
@Component | クラスに付ける |
@Configuration + @Bean | 設定クラスの中で、メソッドに @Bean を付ける |
@Controller、@RestController、@Service、@Repository、@Component をクラスに付けると、Springがそのクラスを認識し、インスタンス化してコンテナに格納します。
一方、@Configuration と @Bean は、少し使い方が異なります。@Configuration を付けた設定クラスの中で、メソッドに @Bean を付けると、そのメソッドが返したインスタンスがコンテナに格納されます。
@Configuration
class ConfigurationClass {
@Bean
MainService mainService() {
return new MainService();
}
}
それぞれの詳しい役割については、「アノテーション編」で解説します。今回は、コンテナへの格納には、このようなアノテーションが使われることを押さえておいてください。
まとめ

「DIの基本編」の内容をまとめます。ポイントは大きく2つです。
- DIとは、必要なクラスをSpringが注入する仕組みです。今回の例では、
MainControllerが必要としているMainServiceをSpringが注入しました - DIが行われるまでの流れは、「インスタンス化 → コンテナへ格納 → 依存関係を確認 → 注入」の4ステップです
このように、「必要なクラスをSpringが準備して、つなぎ合わせる」という考え方が、DIの基本です。
では、Springは必要なクラスをどのような方法で注入するのでしょうか。Spring Bootでは、フィールドやセッター、コンストラクタなど、いくつかの注入方法があります。
次の章では、それぞれの違いと、実務で推奨される注入方法について解説します。


