お問い合わせ

【改訂版】第1章 プログラム構成編|誰もが一度はつまずくSpring Bootを解説

Spring Bootで誰もが一度はつまずきやすいポイントを、Javaの経験が浅い方でも無理なく理解できるように、できるだけ難しい言葉を使わずに解説していくシリーズです。今回は第1章「プログラム構成編」として、Spring Bootが目指す「4つの層」という考え方を、図を使いながらひとつずつ理解していきましょう。

まずは全体像から

まずは、Spring Bootが採用するSpringフレームワークが、どんな形でプログラムを組み立てるのか、その全体像から見ていきます。

Springでは、プログラムを大きく「4つの層」に分けて組み立てていきます。役割の異なる4つのまとまりに分けて整理していく、というイメージです。この考え方は、一般的には「MVC」や「レイヤードアーキテクチャ」などと呼ばれます。

ただ、こうした専門用語は、今の段階では無理に覚えなくて大丈夫です。ここではまず、「Springは役割ごとに4つの層に分けてプログラムを作るんだ」という大きな方針だけつかんでいただければ十分です。

それでは、その4つの層が具体的にどんなものなのか、1つずつ見ていきましょう。

SpringBootの4層構成

こちらが、Spring Bootのプログラム構成の全体像です。プログラムが4つの層に分かれていることが分かります。上から順に、プレゼンテーション層、アプリケーション層、ドメイン層、インフラ層です。

各層の役割を整理すると、次のようになります。

役割
プレゼンテーション層画面表示やUIなど、ユーザーと直接やり取りする部分
アプリケーション層外から来た要求を受け取り、必要な処理を呼び出す入り口
ドメイン層業務ロジック(アプリケーションの中心となる処理)
インフラ層データベースやファイルとの入出力

ここで注目してほしいのは、層と層をつなぐ矢印です。矢印は、上から下への一方向になっています。つまりSpring Bootでは、上の層が下の層を呼び出す、という流れでプログラムを整理します。

なぜ層に分けるのか?

理由は大きく3つあります。

  1. 役割ごとに分担できる ― どの処理をどこに書くのか、置き場所が明確になります。
  2. 指揮系統がはっきりする ― 上の層が下の層を呼ぶ形にすることで、処理の流れを追いやすくなります。
  3. 読みやすく、変更に強くなる ― 役割が分かれているため、あとから修正するときも影響範囲を考えやすくなります。

次に、この4つの層がSpring Bootのコード上でどう表現されるのか、アノテーションとあわせて見ていきましょう。

各層と対応アノテーション

続いて、先ほどの4つの層が、コード上ではどのように表現されるのかを、もう少し実装レベルに落とし込んで見ていきます。

Springでは、それぞれの層を担当するクラスに、「アノテーション」と呼ばれる目印を付けます。これによって、「このクラスはどの層の部品なのか」を、フレームワークに伝えることができます。

層 / 部品アノテーション役割
アプリ層 / コントローラ@Controller / @RestControllerリクエストを受け取り、ドメイン層の処理を呼び出す
ドメイン層 / サービス@Service業務ロジック(アプリの本体となる処理)を書く
インフラ層 / リポジトリ@Repositoryデータベースやファイルへの読み書き
全体設定@Component / @Configuration層に限らず、共通的な部品や設定クラスに付ける

コントローラ(アプリ層)

コントローラには、@Controller、または @RestController を付けます。画面を表示する場合は @Controller、データをそのままやり取りする場合は @RestController を使うことが多いです。

@Controller
public class ControllerClass {
       :
}

サービス(ドメイン層)

サービスには、@Service を付けます。ここには、業務ロジック、つまりアプリの本体となる処理を書いていきます。

@Service
public class ServiceClass {
       :
}

リポジトリ(インフラ層)

リポジトリには、@Repository を付けます。データベースやファイルへの読み書きを担当します。

@Repository
public class RepositoryClass {
       :
}

共通部品・設定クラス

@Component@Configuration は、特定の層に限らず、アプリ全体で使う共通的な部品や、設定クラスに付けるアノテーションです。

@Component
public class ComponentClass {
       :
}

このように、アノテーションを付けるだけで、それぞれのクラスがSpringに「部品」として認識され、管理されるようになります。

ところで、こうして登録されたコントローラ、サービス、リポジトリは、お互いを呼び出して連携します。しかし、コードのどこを見ても、これらを自分で new して組み立てている箇所はありません。では、誰がこれらの部品をつなぎ合わせているのでしょうか。

それを実現しているのが、DI(ディペンデンシー・インジェクション)です。日本語では「依存性の注入」と呼ばれる仕組みです。DIについては、次の章「DI編」でじっくり解説します。ここでは、「アノテーションで登録した部品を、Springが自動でつないでくれる」とイメージしておいてください。

それでは、部品の対応関係が分かったところで、次は実際の処理の流れをシーケンス図で追いかけてみましょう。

処理の流れ(シーケンス)

ここまでに整理した部品を使って、ひとつの処理が始まってから終わるまでの流れを、シーケンス図で時間を追って見ていきましょう。

図の見方は次のとおりです。

  • 時間は上から下へと流れます
  • 上に並んでいるのが登場人物で、左から「画面」「コントローラ」「サービス」「リポジトリ」、右側が記録媒体の「データベースやファイル」です
  • 各登場人物の下に伸びる縦の点線がライフライン、その上に重なる細い長方形は、その部品が処理を行っている時間を表します

それでは、図の番号の順に追っていきます。

行き ― リクエストが奥へ伝わる

  1. リクエスト ― 画面でボタンが押され、コントローラにリクエストが送られます。これが処理の出発点です。
  2. ドメイン呼び出し ― コントローラがドメイン層のサービスを呼び出します。コントローラ自身は業務ロジックを持たず、あくまで処理の「呼び出し役」だという点がポイントです。
  3. データ取得・登録 ― 呼び出されたサービスは、データの取得や登録が必要になると、インフラ層のリポジトリにその処理を依頼します。
  4. 参照・更新 ― リポジトリは、記録媒体であるデータベースやファイルに対して、実際の参照や更新を行います。

帰り ― 結果が画面へ戻る

  1. 結果 ― リポジトリが記録媒体から結果を受け取ります。記録媒体へのアクセスは、必ずこのリポジトリを介して行われる、という点を押さえてください。
  2. 結果を返す ― リポジトリからサービスへ結果を返します。
  3. 処理結果 ― サービスからコントローラへ処理結果を返します。
  4. 画面へ返す ― 最後にコントローラから画面へと結果を返し、画面に結果が表示されます。

このように、それぞれの層が自分の役割だけに専念し、決められた順番で「呼び出し」と「返却」を繰り返していくのが、Springフレームワークが目指す処理の流れです。

まとめ

それでは、この「プログラム構成編」の内容をまとめます。ポイントは大きく2つです。

  1. 4層 = プレゼン → アプリ → ドメイン → インフラ ― Springのプログラムは4つの層で構成され、プレゼンテーション層からインフラ層へと、決められた順番で呼び出されていきます。
  2. 各層に対応するアノテーションを付ける ― それぞれの層を担当するクラスに、@Controller@Service@Repository といった対応するアノテーションを付け、Springに「どの層の部品か」を認識させます。

この「層ごとに役割を分ける」こと。そして「アノテーションで部品として登録する」こと。この2つの考え方が、Springアプリケーションの土台になります。

そして、アノテーションで登録した部品同士を、どうやってつなぎ合わせるのか。その答えが、次の章でお話しするDI(依存性の注入)です。