Spring에서 Controller, Service, Repository 계층 구조란?

Spring Framework 기반의 애플리케이션을 개발할 때 가장 자주 등장하는 개념이 바로 Controller - Service - Repository로 이어지는 3계층 구조입니다.

각 계층의 역할과 왜 이러한 구조를 사용하는지, 실무에서 어떻게 활용해야 하는지를 중심으로 자세히 알려드리겠습니다.

 

1. 왜 계층 구조를 사용하는가?

애플리케이션이 성장할수록 유지보수가 어려워지고 변경 사항이 다른 부분에 영향을 줄 수 있습니다. 이를 방지하기 위해 코드의 책임을 분리하고 명확한 역할을 나누는 것이 중요합니다. Controller, Service, Repository 패턴은 이러한 관심사의 분리를 구조화하는 대표적인 예입니다.

 

2. 각 계층의 역할

2.1 Controller 계층

Controller는 클라이언트(웹 브라우저 또는 외부 시스템)로부터 들어온 요청을 처리하는 진입 지점입니다. 주로 HTTP 요청을 받아서 적절한 Service를 호출하고, 그 결과를 응답합니다.

@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

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

    @GetMapping("/{id}")
    public UserDto getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}

Controller는 절대 비즈니스 로직을 포함하지 않아야 하며, 요청과 응답의 흐름을 조정하는 데 집중합니다.

 

2.2 Service 계층

Service는 실제 비즈니스 로직을 처리하는 계층입니다. 여러 Repository를 조합하거나 트랜잭션 처리, 복잡한 도메인 로직이 이곳에서 수행됩니다.

@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 EntityNotFoundException("사용자를 찾을 수 없습니다."));
        return new UserDto(user);
    }
}

Service는 Controller와 Repository 사이의 중간자 역할을 하며, 애플리케이션의 핵심 로직이 모이는 곳입니다.

 

2.3 Repository 계층

Repository는 데이터베이스와 직접 통신하는 계층으로, JPA나 MyBatis와 같은 ORM 또는 쿼리 매퍼를 통해 실제 데이터를 조회하거나 저장합니다.

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // JpaRepository가 기본적인 CRUD 기능을 제공
}

Repository는 데이터 처리에만 집중하고, 로직은 포함하지 않는 것이 원칙입니다.

 

3. 계층 구조의 장점

  • 관심사의 분리 (Separation of Concerns): 각 계층이 자기 역할에만 집중할 수 있어 유지보수가 수월합니다.
  • 테스트 용이성: 단위 테스트와 통합 테스트 작성이 구조적으로 유리합니다.
  • 재사용성 확보: Service 계층을 재활용하여 여러 Controller에서 사용할 수 있습니다.
  • 의존성 역전 원칙 적용: 비즈니스 로직이 인프라(Repository)에 의존하지 않도록 설계할 수 있습니다.

 

4. 실무에서의 유의사항

  • Controller에 비즈니스 로직이 섞이지 않도록 주의하세요.
  • Service는 가능한 한 간결하게 유지하되, 비즈니스의 핵심 처리만을 담당하세요.
  • Repository는 쿼리 외의 로직을 넣지 않는 것이 좋습니다.
  • 계층 간 의존은 항상 위에서 아래 방향 (Controller → Service → Repository) 으로만 흐르도록 설계하세요.

 

5. 마무리

Spring에서 Controller-Service-Repository 계층 구조는 단지 형식적인 구조가 아닙니다. 코드를 읽는 사람, 유지보수하는 사람 모두가 이해하기 쉬운 구조를 만들기 위한 기본적인 설계 패턴입니다.