はじめに
Spring Boot のコードを書いていると、
Controller / Service / Repository の
3 つの層をよく目にします。
その中でも Service 層 は、
「なんとなく真ん中にあるけど、何をする層なの?」
と迷いやすい場所です。
この記事では、Service 層の役割を
やさしく・実務で役立つ形 で整理していきます。
まずは全体像から見ていきましょう。
Service 層とは
一言でいうと、
「アプリのビジネスロジックをまとめる“司令塔”の層」
です。
- Controller → リクエストの受付
- Service → 業務処理の中心
- Repository → DB とのやり取り
この中で Service は、 アプリの“頭脳” のような役割を持っています。
Service 層の役割を具体的に整理する
ビジネスロジックを実装する
アプリが提供する“本来の処理”を書く場所です。
例:
- ユーザー登録のルール
- 在庫チェック
- ポイント計算
- 料金の算出
@Service
public class OrderService {
public int calculatePrice(int base, int discount) {
return base - discount;
}
}Controller に書くと肥大化するため、
Service に集約します。
複数の Repository を組み合わせる
Service は複数のデータソースを扱えます。
例:
- ユーザー情報を取得
- 注文情報を取得
- それらを組み合わせてレスポンスを作る
@Service
public class UserDetailService {
private final UserRepository userRepository;
private final OrderRepository orderRepository;
public UserDetailService(UserRepository userRepository, OrderRepository orderRepository) {
this.userRepository = userRepository;
this.orderRepository = orderRepository;
}
public UserDetailResponse getDetail(Long id) {
User user = userRepository.findById(id).orElseThrow();
List<Order> orders = orderRepository.findByUserId(id);
return new UserDetailResponse(user, orders);
}
}Controller ではなく Service が担うべき処理です。
トランザクション管理を行う
データの整合性を保つために
@Transactional を付けるのは Service 層が基本です。
@Transactional
public void createOrder(OrderRequest req) {
// 複数の DB 操作をまとめて実行
}Controller に付けるのはアンチパターンです。
業務的なバリデーションを行う
入力チェック(形式)は Controller / DTO で行いますが、
業務ルールのチェック は Service の役割です。
例:
- 在庫が 0 の商品は購入できない
- 同じメールアドレスは登録できない
- 退会済みユーザーはログインできない
if (user.isDeleted()) {
throw new BusinessException("退会済みユーザーです");
}例外を投げて ControllerAdvice に渡す
Service 層で例外を投げ、
ControllerAdvice でレスポンスを整えるのが実務的です。
throw new UserNotFoundException("ユーザーが見つかりません");Service 層に書かないこと
HTTP の処理
- @RequestBody
- @RequestParam
- @PathVariable
これらは Controller の役割です。
DB の直接操作
SQL や ORM の操作は Repository に任せます。
画面やレスポンスの整形
Service は“処理”に集中し、
レスポンスの形は Controller が決めます。
実務でよくあるアンチパターン
Controller にロジックを書いてしまう
→ 画面が増えると地獄になります。
Service がただの中継役になる
return repository.findById(id);→ これでは Service の意味がありません。
Repository に業務ロジックを書く
→ DB に依存した設計になり、変更に弱くなります。
Service 層をもっと活かすポイント
DTO を使って Controller と役割を分離
public UserResponse findUser(Long id)例外クラスでエラーを整理
throw new BusinessException("ルール違反です");テストしやすい構造にする
Service は単体テストがしやすい層です。
まとめ
Service 層は、
「アプリのビジネスロジックを担う中心の層」
です。
- 業務処理をまとめる
- 複数の Repository を組み合わせる
- トランザクション管理
- 業務的なバリデーション
- 例外を投げて Controller に渡す
難しく聞こえますが、
「受付(Controller)とデータ係(Repository)の間で、頭脳として働く層」
と理解できれば十分です。

Service 層の役割を理解すると、
Controller と Repository の境界が一気にクリアになります。
ロジックが整理されるだけで、設計もテストもぐっと楽になります。
あなたの開発が、今日より少しだけ楽になりますように。

司令塔ってかっこいいね…みんなをまとめてくれる存在、すてき…

コメント