스프링에게 "이 클래스를 Bean으로 등록해줘"라고 알려주는 가장 기본적인 어노테이션
@Component
public class MyUtil {
public String formatDate(LocalDate date) {
return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
}
@Component를 붙이면 스프링이 앱을 시작할 때 이 클래스를 찾아서 객체를 만들고, 컨테이너에 Bean으로 보관한다. 이걸 컴포넌트 스캔(Component Scan)이라고 한다
✨ TIP : @SpringBootApplication 어노테이션 안에 @ComponentScan이 포함되어 있다. 그래서 메인 클래스가 있는 패키지와 그 하위 패키지에 있는 모든 @Component 클래스를 자동으로 찾는다
com.myname.board/
├── BoardApplication.java ← @SpringBootApplication (여기서부터 스캔 시작)
├── controller/
│ └── PostController.java ← ✅ 스캔됨
├── service/
│ └── PostService.java ← ✅ 스캔됨
└── repository/
└── PostRepository.java ← ✅ 스캔됨
com.myname.other/
└── SomeClass.java ← ❌ 다른 패키지라서 스캔 안 됨
이것 때문에 프로젝트의 모든 코드는 반드시 메인 클래스와 같은 패키지 또는 하위 패키지에 있어야 한다
사실 이 세 어노테이션은 전부 @Component를 포함하고 있다. 소스 코드를 까보면:

// 실제 스프링 소스 코드 (간략화)
@Component
public @interface Service { }
@Component
public @interface Repository { }
@Component
public @interface Controller { }
그러면 전부 @Component를 쓰면 되지, 왜 굳이 나눠놨을까? (2가지 이유 존재)
➡️ 이유 1: 역할을 명확하게 표현
코드를 읽는 사람이 이 클래스가 어떤 역할인지 바로 알 수 있다
@Controller → "아, 이건 웹 요청을 받는 클래스구나"
@Service → "아, 이건 비즈니스 로직을 처리하는 클래스구나"
@Repository → "아, 이건 DB와 통신하는 클래스구나"
➡️ 이유 2: 스프링이 추가 기능을 제공
각 어노테이션은 @Component 이상의 일을 한다:
@Controller : 이 클래스의 메서드 반환값을 뷰 이름으로 처리 (HTML 반환)@RestController : @Controller + @ResponseBody, 반환값을 JSON으로 처리@Repository : DB 관련 예외를 스프링의 DataAccessException으로 자동 변환@Service : 비즈니스 로직 계층을 명시3계층 아키텍처와 매핑하면 이렇다:
[클라이언트 요청]
↓
┌─────────────────────┐
│ @RestController │ ← 요청을 받고, 응답을 반환
│ PostController │ URL 매핑, 요청 데이터 추출
└─────────┬───────────┘
↓
┌─────────────────────┐
│ @Service │ ← 비즈니스 로직 처리
│ PostService │ 검증, 계산, 변환, 트랜잭션
└─────────┬───────────┘
↓
┌─────────────────────┐
│ @Repository │ ← DB 접근
│ PostRepository │ 저장, 조회, 수정, 삭제
└─────────────────────┘