【プログラミング】【java】Springのレイヤー構造について - j-komatsu/myCheatSheet GitHub Wiki

Springのレイヤー構造について

1. Springのレイヤー構造とは?

📌 初学者向け

Springでは、アプリケーションの役割を明確に分けるために、以下のようなレイヤー構造を採用します。

  • コントローラー層(Controller): ユーザーのリクエストを受け取り、レスポンスを返す
  • サービス層(Service): 業務ロジックを担当する
  • リポジトリ層(Repository): データベースへのアクセスを担当する
  • ドメイン層 / ロジック層(Domain / Logic): ビジネスルールやエンティティを定義する

この構造を用いることで、責務を分離し、メンテナンス性を向上させることができます。

なぜレイヤーを分けるのか?

  1. 保守性向上: それぞれのレイヤーが独立しているため、一部を修正しても他の部分に影響を与えにくい。
  2. 可読性向上: コードが整理されており、どの処理がどこで行われるかが明確。
  3. 再利用性向上: 共通の業務ロジックをサービス層に置くことで、他のコントローラーやバッチ処理でも同じロジックを利用可能。
  4. テスト容易性: 各レイヤーを個別にテストできるため、単体テストが容易になる。

📌 専門者向け

Springのレイヤー構造は、Clean Architectureや**DDD(ドメイン駆動設計)**の考え方に基づいて設計されることが多いです。

  • ControllerServiceRepository の順に処理を流す
  • DTO(Data Transfer Object) を使ってデータの受け渡しを行う
  • DI(依存性注入) を用いて各コンポーネントを疎結合に保つ
  • トランザクション管理(@Transactional)を適切に使用する

こうした設計を守ることで、拡張性の高いシステムを構築できます。

2. レイヤーごとの特徴

graph TD;
    Controller -->|呼び出し| Service;
    Service -->|業務ロジック| Repository;
    Repository -->|DB操作| Database;
Loading
レイヤー 役割 使用するアノテーション
コントローラー層 HTTPリクエストを処理しレスポンスを返す @RestController @GetMapping("/user")
サービス層 業務ロジックを実装 @Service public User getUser()
リポジトリ層 DBとのやり取りを実装 @Repository UserRepository extends JpaRepository
ドメイン層 ビジネスルールを定義 なし class User {}

各レイヤーの目的と利点

  • コントローラー層

    • クライアント(ブラウザやモバイルアプリ)からのリクエストを受け付け、適切なレスポンスを返す。
    • 例: GET /users/1 を受け取って、UserDTO を返す。
    • @RestController を使用してJSONデータのやりとりを行う。
  • サービス層

    • 業務ロジックを実装し、コントローラー層や他のサービスから呼び出される。
    • 例: ユーザー情報を取得し、加工したデータを返す。
    • 変更が必要になった場合、ビジネスロジックをサービス層だけに集中させることで修正が容易。
  • リポジトリ層

    • データベースとのやり取りを担当し、SQLの抽象化を行う。
    • 例: findById(id) メソッドを使用して、データベースから特定のユーザー情報を取得する。
    • JpaRepository を継承することで、基本的なCRUD操作が簡単に実装可能。
  • ドメイン層(エンティティ)

    • データの構造を定義し、システム全体で統一したモデルを提供する。
    • 例: User エンティティには idname を含む。
    • DDDの考え方に基づき、エンティティのバリデーションや関連ビジネスルールを定義することもある。

3. 実装例

📌 サンプルコード(入力・出力例付き)

コントローラー層

@RestController
@RequestMapping("/users")
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }
}

サービス層

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public UserDTO getUserById(Long id) {
        User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
        return new UserDTO(user.getId(), user.getName());
    }
}

リポジトリ層

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

ドメイン層(エンティティ)

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    // ゲッターとセッター
}

📌 入出力例

リクエスト

GET /users/1

レスポンス

{
    "id": 1,
    "name": "Taro Yamada"
}

このようにSpringのレイヤー構造を適切に設計することで、保守性・拡張性の高いアプリケーションを構築できます。

⚠️ **GitHub.com Fallback** ⚠️