본문 바로가기
Daily Dev Q&A 정리 템플릿

25.12.26 스프링 어노테이션 (@Component, @Service, @Repository, @Controller)

by teg0 2025. 12. 26.

스프링에서 @Component, @Service, @Repository, @Controller는 모두 스테레오 타입(Stereotype) 어노테이션이라고 불린다. 이들은 스프링 컨테이너가 어떤 클래스를 빈(Bean)으로 등록할지 알려주는 표식 역할을 한다.

 

공통점: 빈 스캐닝 (Component Scanning)

이 어노테이션들이 붙은 클래스는 스프링이 기동 될 때 자동으로 찾아내서(Scanning) IoC 컨테이너에 객체(Bean)를 등록한다.

 

@Service, @Repository, @Controller 이 어노테이션들은 @Component에게 상속(메타 어노테이션)을 받고 있다.

 

각 어노테이션의 역할과 차이점

스프링은 계층별 아키텍처(Layered Architecture)를 권장하기 때문에, 각 계층의 목적에 맞게 어노테이션을 나누어 사용한다.

어노테이션 위치(Layer) 주요 역할 및 특징
@Component  공통 / 기타 가장 기본이 되는 어노테이션
특정 계층에 속하지 않는 유틸리티, 헬퍼 클래스 등에 사용된다.
@Controller Presentation 웹 요청(HTTP Reqeust)를 받고 응답을 반환하는 컨트롤러임을 명시한다.
Spring MVC에서 핸들러 매핑이 이를 인식한다.
@Service Business 비즈니스 로직이 수행되는 곳임을 나타낸다.
특별한 기술적 기능은 없지만, 여기에 핵심 로직이 있다는 가독성을 높여준다.
@Repository Persistence DB 접근 로직(DAO)이 있는 클래스에 사용한다.
가장 큰 특징은 DB 예외를 스프링의 공통 예외(DataAccessException)로 변환해주는 것이다.

각 어노테이션 예시

@Controller (또는 @RestController)

외부의 요청을 가장 먼저 받는 프레젠테이션 계층

@RestController // @Controller + @ResponseBody (JSON 응답에 최적화)
@RequestMapping("/members")
public class MemberController {

    private final MemberService memberService;

    // 생성자 주입 (DI)
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

    @PostMapping("/join")
    public String join(@RequestBody MemberDto memberDto) {
        memberService.register(memberDto);
        return "회원가입 성공!";
    }
}

 

@Service

핵심 로직이 들어가는 비즈니스 계층

@Service
public class MemberService {

    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public void register(MemberDto dto) {
        // 1. 중복 회원 검증 같은 비즈니스 로직 수행
        validateDuplicateMember(dto.getEmail());
        
        // 2. DB 저장을 위해 Repository 호출
        memberRepository.save(dto.toEntity());
    }

    private void validateDuplicateMember(String email) {
        // 중복 검증 로직...
    }
}

 

@Repository

데이터베이스에 접근하는 데이터 접근 계층(Persistence Layer)

@Repository
public class MemberRepository {

    // 실제로는 EntityManager나 JdbcTemplate 등을 사용함
    public void save(MemberEntity member) {
        // DB에 저장하는 쿼리 실행
        // 여기서 발생하는 DB 에러는 스프링의 DataAccessException으로 변환됨
        System.out.println("DB에 회원 저장 완료: " + member.getName());
    }
}

 

@Component

위의 세 계층에 속하지 않지만, 스프링 빈으로 관리되어야 하는 일반적인 유틸리티나 헬퍼 클래스

@Component
public class PasswordEncoder {

    public String encode(String rawPassword) {
        // 비밀번호를 암호화하는 공통 유틸리티 로직
        return "encrypted-" + rawPassword;
    }
}

 

용어 정리

핸들러 매핑 (Handler Mapping): 어떤 요청을 어떤 컨트롤러가 처리할지 결정하는 지도

  • 역할: 웹 브라우저로부터 HTTP 요청(예: GET /users/1)이 들어왔을 때, 스프링의 문지기인 DispatcherServlet은 이 요청을 누가 처리해야 할지 모릅니다. 이때 핸들러 매핑에게 "이 URL은 누가 담당하니?"라고 물어보고, 그 요청을 처리할 컨트롤러(핸들러)를 찾아오는 역할을 한다.
  • 작동 방식: 우리가 클래스에 @Controller를 붙이고 메서드에 @RequestMapping이나 @GetMapping을 사용하는 것이 바로 핸들러 매핑에 "이 URL은 내가 처리할게!"라고 등록하는 과정이다.
  • 비유: 백화점 안내 데스크(Handler Mapping)가 손님이 찾는 매장(Controller)의 위치를 알려주는 것과 같다.

 

 

DataAccessException: 데이터베이스 오류를 스프링 방식의 언어로 번역한 예외

 

  • 배경: DB마다 오류 코드가 다르다. MySQL에서 발생하는 오류와 Oracle에서 발생하는 오류가 서로 다른 예외(Exception)를 던지면, 개발자는 DB를 바꿀 때마다 예외 처리 코드도 다 고쳐야 한다.
  • 역할: 스프링은 DB 종류에 상관없이 일관된 예외 처리를 할 수 있도록 각 DB의 예외를 잡아 스프링만의 공통 예외인 DataAccessException으로 변환해 준다.
  • 특징:
    1. 런타임 예외(Unchecked Exception): 일일이 try-catch로 잡지 않아도 되므로 코드가 깔끔해진다.
    2. 예외 추상화: @Repository 어노테이션의 핵심 기능 중 하나가 바로 해당 계층에서 발생하는 기술적인 에러(SQLException 등)를 이 DataAccessException으로 변환해 주는 것이다.
  • 비유: 전 세계의 다양한 언어(각 DB의 예외)를 공용어인 영어(DataAccessException)로 통역해 주는 것과 같다.

 

왜 @Component로 사용하지 않고 나눠서 사용할까?

모두 똑같이 빈으로 등록되는데 굳이 나누어 쓰는 이유는 크게 3가지이다.

  1. 가독성과 의미 전달: 코드를 딱 봤을 때 "아, 이 클래스는 비즈니스 로직을 담당하는구나"라고 바로 파악할 수 있다.
  2. AOP(관점 지향 프로그래밍) 적용: 특정 계층에만 공통 기능을 적용하고 싶을 때(예: 모든 Service 계층에 로그 남기기) 포인트컷 설정을 쉽게 할 수 있다.
  3. 계층별 특수 기능 부여: * @Repository는 DB 예외 변환 기능을 제공한다.
    • @Controller는 스프링 MVC에서 컨트롤러로 인식되어 매핑 규칙에 포함됩니다.

 

면접 답변식 요약

모두 스프링 컨테이너가 관리하는 빈(Bean) 임을 나타내는 표식입니다. 근본적으로는 모두 @Component를 포함하고 있어 컴포넌트 스캔의 대상이 된다는 공통점이 있습니다.

차이점은 애플리케이션 계층 구조에 따른 역할 분담에 있습니다.

@Controller는 웹 요청과 응답을 처리하는 프레젠테이션 계층에서 사용되며, @Service는 핵심 비즈니스 로직이 담긴 서비스 계층을 명시합니다.

@Repository는 데이터 접근 계층에서 사용되며, 특히 데이터베이스 예외를 스프링의 예외 추상화 계층으로 변환해 주는 기술적 특징이 있습니다.

마지막으로 @Component는 이러한 계층에 속하지 않는 일반적인 빈을 등록할 때 사용합니다.

이렇게 나누어 사용하는 이유는 코드의 가독성을 높이고, AOP 등을 활용해 계층별로 공통 기능을 유연하게 적용하기 위함입니다.