【プログラミング】【java】Springのレイヤー構造について - j-komatsu/myCheatSheet GitHub Wiki
Springでは、アプリケーションの役割を明確に分けるために、以下のようなレイヤー構造を採用します。
- コントローラー層(Controller): ユーザーのリクエストを受け取り、レスポンスを返す
- サービス層(Service): 業務ロジックを担当する
- リポジトリ層(Repository): データベースへのアクセスを担当する
- ドメイン層 / ロジック層(Domain / Logic): ビジネスルールやエンティティを定義する
この構造を用いることで、責務を分離し、メンテナンス性を向上させることができます。
なぜレイヤーを分けるのか?
- 保守性向上: それぞれのレイヤーが独立しているため、一部を修正しても他の部分に影響を与えにくい。
- 可読性向上: コードが整理されており、どの処理がどこで行われるかが明確。
- 再利用性向上: 共通の業務ロジックをサービス層に置くことで、他のコントローラーやバッチ処理でも同じロジックを利用可能。
- テスト容易性: 各レイヤーを個別にテストできるため、単体テストが容易になる。
Springのレイヤー構造は、Clean Architectureや**DDD(ドメイン駆動設計)**の考え方に基づいて設計されることが多いです。
- Controller → Service → Repository の順に処理を流す
- DTO(Data Transfer Object) を使ってデータの受け渡しを行う
- DI(依存性注入) を用いて各コンポーネントを疎結合に保つ
- トランザクション管理(@Transactional)を適切に使用する
こうした設計を守ることで、拡張性の高いシステムを構築できます。
graph TD;
Controller -->|呼び出し| Service;
Service -->|業務ロジック| Repository;
Repository -->|DB操作| Database;
レイヤー | 役割 | 使用するアノテーション | 例 |
---|---|---|---|
コントローラー層 | 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
エンティティにはid
とname
を含む。 - DDDの考え方に基づき、エンティティのバリデーションや関連ビジネスルールを定義することもある。
@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のレイヤー構造を適切に設計することで、保守性・拡張性の高いアプリケーションを構築できます。