お問い合わせ

誰もが一度はつまずくSpring Bootを解説♪-DI編-【若手Javaエンジニア向け】

こんにちは。ステックアップアカデミー講師のかびらです。現役のITエンジニアであり、かつAFP保持者として、このチャンネルを通して、ITエンジニアとフリーランスに必要な、ITとお金に関する情報を配信しています。

今回から主に若手Javaエンジニアの方々に向けて、「誰もは一度はつまずく、Spring Bootを解説」というシリーズをお届けします。私はSpring Bootを本業で使用して4年ほど経ちますが、私自身Spring Bootを使用していてつまずいたポイントが多くありました。また私よりも後に参画した若手エンジニアの方が、私と同じような場所でつまずく姿を何度も目撃しました。そこでこのシリーズでは、誰もが共通してつまずきやすいポイントを、Javaのスキルや経験が浅い若手エンジニアでも理解できるように、極力難しい用語を使わずに解説していきたいと思います。今回は、Spring Bootを使用するにあたって、絶対に抑えておくべき基礎知識、DIについてわかりやすく解説します。

DI

Spring Bootを使用したプロジェクトに参画すると必ず理解を求められる用語が「DI」です。私も「DI」という用語をはじめて聞いたときは凄く難しい印象を持ちました。しかし、今回解説する内容のイメージを持てれば「何だそういうことか!」とすんなり理解することができるようになると思います。それでは、DIについてさっそく学んでいきましょう。

DIとは?

まず「DI」とはどういう意味なのでしょうか。「DI」とは「Dependency Injection」の頭文字を取った用語です。「Dependency」は「依存性」、「Injection」は「注入」という意味です。そのため、「DI」を日本語に直訳すると「依存性注入」という意味になります。「依存性注入」という言葉、いまいちピンと来ないのではないでしょうか。「依存性注入」とはどういうことなのか、わかりやすく解説します。

依存性注入(DI)とは?

「依存性注入」について解説します。例として図のように「メインクラス」と「部品クラス」の2つのクラスがあるとします。「メインクラス」の「メインメソッド」の中には、「部品クラス」の「部品A」を呼び出す処理があります。このような処理では、「メインクラス」の「メインメソッド」は「部品クラス」の「部品A」がないと正常に動作することができませんよね。この状態が「メインクラス」と「部品クラス」が「互いに依存関係」にあるという意味になります。

この「メインクラス」の「メインメソッド」を正常に動作させるためには、「部品クラス」の「部品A」を「メインクラス」の「メインメソッド」に入れてあげる必要があります。この「部品A」を「メインメソッド」に入れ込む動作のことを「注入」と呼んでいます。つまり、「メインクラス」と「部品クラス」がお互いに「依存関係」にある場合、依存している箇所に部品を使えるように「注入」してあげることを「依存性注入(DI)」と呼んでいます。

「依存性注入(DI)」のイメージを持てたでしょうか。実はこの「依存性注入(DI)」を行うためには、ある条件が必要です。その条件とは「お互いのクラスが内部メモリに格納されている」ことです。次に、内部メモリに格納して「依存性注入(DI)」を行うイメージを見ていきましょう。

まずは内部メモリへの格納のイメージです。まだインスタンス化されていない「メインクラス」と「部品クラス」があるとします。Spring Bootでは起動直後に、この「メインクラス」と「部品クラス」をインスタンス化します。そしてインスタンス化した2つのクラスを内部メモリへと格納します。

「メインクラス」と「部品クラス」を内部メモリに格納することができました。次に、Spring Bootでは、内部メモリ内にある「メインクラス」と「部品クラス」が「お互いに依存関係にあること」とを確認します。「依存関係」があれば、「メインクラス」に「部品A」を注入します。これが「お互いのクラスを内部メモリに格納」し、「依存性注入(DI)する」までの流れです。

DIのコード例

続いて、「DI」の実際のコード例を見てみましょう。画像の左側に示しているのが「メインクラス」です。「メインクラス」内に「メインメソッド」が定義されています。「メインメソッド」では、「バーツA」の「getTextメソッド」を呼び出す処理が記述されています。一方で、画像の右側に示しているのが「部品クラス」です。「部品クラス」は「パーツA」と名前を定義しています。その「パーツA」内で「getTextメソッド」を定義しています。「getTextメソッド」は「Hellow PartsA」という単純な文字列を返すメソッドです。

この2つのクラス間で「DI」を行います。「DI」を行うためにはアノテーションの指定が必要です。まず「メインクラス」に「@RestController」というアノテーションを付与しています。この「@RestController」付与することで、「メインクラスを内部メモリに格納してほしい」という指示になります。一方、「部品クラス」には「@Component」というアノテーションを付与しています。この「@Component」を付与することによって、「パーツAを内部メモリに格納してほしい」という指示をします。「@RestController」や「@Component」アノテーションとは何ぞや?と疑問を持たれた方もいると思いますが、これらのアノテーションの意味については次のテーマで解説しようと思います。今回は「DIするために必要な”おまじない”」だと思って聞いてください。

「メインクラス」で「パーツAを注入」するために、「メインクラス」のメンバ変数である「パーツA」に「@Autowired」というアノテーションを付与します。「@Autowired」は「パーツAをメインクラスに注入してほしい」という指示になります。この「@Autowired」を付与することで、内部メモリに格納されている「パーツAをメインクラスに注入」することができます。「パーツA」が注入できれば、「メインメソッド」で「パーツA」の「getTextメソッド」を使用できるようになります。

DI成功

実際にデバッグで動かして、「DI」の仕組みを動画で確認してみましょう。左側のクラスが「メインコントローラ」で右側のクラスが「パーツA」です。「メインコントローラ」には「@RestContoroller」を付与しており、「パーツA」には「@Component」を付与しています。「メインコントローラ」のメンバ変数には「パーツA」をDIするために「@Autowired」を付与しています。「パーツA」には「getTextメソッド」が用意されており、「メインコントローラ」の「メインメソッド」は、「DI」された「パーツA」の「getTextメソッド」が呼び出されます。「メインメソッド」は、「パーツA」の「getTextメソッド」から受け取った「Hellow PartsA」をリターンする単純なメソッドになっています。それではこのアプリをデバッグ起動して、動きを確認してみましょう。

デバッグでtext変数の中身を確認すると「Hellow PartsA」が設定されていることがわかります。これは、「メインコントローラ」に「DI」された「パーツA」が、「メインコントローラ」内で使用できるようになり、「getTextメソッド」を正常に呼び出せたためです。「@RestContoroller」の返却値も、正常に「Hellow PartsA」が出力されていることが確認できます。

DI失敗

先ほど説明した内容はDIの成功例でした。今度は失敗例も見てみましょう。「DI」をするには「お互いに内部メモリへの格納が必要」だと説明しました。今回はその内部メモリへの格納指示である「@Component」を外してみます。

いかがでしょうか。「メインコントローラ」に「パーツA」を「DI」しようとしているのにも関わらず、内部メモリに「パーツA」がない状態、つまり「@Component」を付与していない場合は、アプリを起動した直後にエラーになることが動画で確認できます。

内部メモリへ格納するアノテーションの種類

ここまでの説明で「DI」のイメージを掴めましたでしょうか?最後に、内部メモリへ格納するアノテーションの種類の一部をご紹介します。

こちらに内部メモリへ格納するアノテーションをコードと共に示しています。「@Controller」、「@RestController」、「@Service」、「@Component」、「@Repository」。「@Bean」は少し特殊で、「@Configuration」と共に使用します。

これらが「DI」するためにSpring Bootに用意されているアノテーションの一部です。それぞれの詳細なアノテーションの説明はまた次の動画で解説と思います。今回は「内部メモリへ格納するアノテーションにはこのような種類があるんだな」ということを覚えておいてください。

さいごに

今回の講義はここまでです。Spring Bootをこれから学ぶ人やSpring Bootを使い始めたけど仕組みがよくわからないという方々には参考になる内容ではなかったでしょうか。次回はそれぞれのアノテーションの意味について解説予定です。それではまた次回の講義でお会いしましょう。