Spring/Spring 기초 및 세팅

Spring day 3

seungwon-1 2026. 6. 20. 19:50

[Spring 입문 3일차] Bean과 컨테이너, 컴포넌트 스캔

들어가며

2일차에서 IoC와 DI를 다루며 Bean과 컨테이너라는 단어가 잠깐 등장했다. Spring이 객체를 대신 만들어 관리하고, 필요한 곳에 주입해 준다는 큰 그림까지 잡았다.

오늘은 그 안으로 한 걸음 더 들어간다. Bean이 정확히 무엇이고, 컨테이너가 어떤 역할을 하며, Spring이 어떻게 클래스를 찾아 Bean으로 등록하는지를 살펴본다.

Bean이란 무엇인가

Bean은 Spring 컨테이너가 생성하고 관리하는 객체를 말한다.

우리가 직접 new로 만든 객체는 Bean이 아니다. Spring이 직접 만들어서 컨테이너 안에 보관하고, 필요할 때 꺼내 주입해 주는 객체만 Bean이라고 부른다. 2일차에서 생성자로 주입받았던 PaymentService가 바로 Bean이었다.

Spring 컨테이너

Spring 컨테이너는 Bean을 만들고, 보관하고, 서로 연결해 주는 공간이다. 정식 명칭은 ApplicationContext이며, 애플리케이션이 시작될 때 함께 생성된다.

컨테이너가 하는 일을 정리하면 다음과 같다.

  • 등록 대상 클래스를 찾아 객체로 만든다
  • 만든 객체(Bean)를 보관한다
  • Bean끼리 필요한 관계를 찾아 주입해 준다

1일차에서 서버를 실행했을 때, 콘솔에 로그가 주르륵 출력되며 잠깐의 시간이 걸렸다. 그 사이에 컨테이너가 만들어지고 필요한 Bean들이 등록되는 과정이 진행된 것이다.

Bean을 등록하는 두 가지 방법

클래스를 Bean으로 등록하는 방법은 크게 두 가지다.

1. 어노테이션 + 컴포넌트 스캔

가장 흔하게 쓰는 방식이다. 클래스에 @Component 계열 어노테이션을 붙이면, Spring이 알아서 찾아 Bean으로 등록한다.

@Service
public class OrderService {
    private final PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

@Service가 붙어 있으므로 OrderService는 자동으로 Bean이 된다. 개발자가 등록을 위해 따로 할 일은 없다.

2. @Bean으로 직접 등록

직접 만들기 어렵거나, 내가 작성하지 않은 외부 라이브러리의 객체를 Bean으로 등록할 때 사용한다. @Configuration을 붙인 클래스 안에서 @Bean 메서드로 객체를 반환하면 된다.

@Configuration
public class AppConfig {

    @Bean
    public PaymentService paymentService() {
        return new PaymentService();
    }
}

입문 단계에서는 첫 번째 방식(컴포넌트 스캔)을 주로 쓰게 된다. 두 번째 방식은 이런 방법도 있다는 정도만 알아 두면 된다.

컴포넌트 스캔은 어떻게 동작하는가

그렇다면 Spring은 @Component가 붙은 클래스를 어떻게 찾아낼까. 그 역할을 하는 것이 컴포넌트 스캔이다.

1일차에 봤던 시작 클래스의 @SpringBootApplication 안에는 사실 @ComponentScan이 포함되어 있다. 이 어노테이션이 시작 클래스가 위치한 패키지와 그 하위 패키지를 전부 훑으면서, @Component 계열이 붙은 클래스를 찾아 Bean으로 등록한다.

여기서 중요한 점이 하나 있다. 스캔은 시작 클래스의 패키지를 기준으로 아래쪽만 탐색한다는 것이다. 그래서 보통 시작 클래스(예: DemoApplication)를 프로젝트의 최상위 패키지에 두고, 나머지 클래스들을 그 하위에 배치한다. 1일차에서 만든 기본 구조가 이미 이 규칙을 따르고 있었다.

@Component 계열 어노테이션 구분

@Component 계열에는 여러 종류가 있다. 기능상으로는 모두 Bean으로 등록된다는 점에서 같지만, 역할을 드러내기 위해 구분해서 쓴다.

  • @Component : 가장 기본이 되는 어노테이션이다.
  • @Controller : 웹 요청을 받아 처리하는 계층에 붙인다.
  • @Service : 비즈니스 로직을 담는 계층에 붙인다.
  • @Repository : 데이터베이스에 접근하는 계층에 붙인다.

이렇게 나눠 쓰면 클래스만 봐도 그 역할이 한눈에 드러난다. 참고로 @Repository는 데이터 접근 과정에서 발생하는 예외를 다루기 쉬운 형태로 바꿔 주는 기능도 함께 가지고 있는데, 이 부분은 DB를 다루는 편에서 다시 언급한다.

Bean은 기본적으로 하나만 만들어진다

Spring의 Bean은 기본적으로 컨테이너당 하나만 생성되어 공유된다. 이를 싱글톤(Singleton)이라고 한다.

같은 OrderService를 여러 곳에서 주입받더라도, 실제로는 모두 동일한 하나의 객체를 함께 사용한다. 매번 새로 만들지 않으므로 메모리를 효율적으로 쓸 수 있다. 지금 단계에서는 "Bean은 보통 하나만 만들어져 재사용된다"는 정도만 기억해도 충분하다.

정리

정리해 보면, Bean은 Spring 컨테이너가 만들어 관리하는 객체이고, 컨테이너는 그 Bean을 생성하고 보관하고 주입해 주는 공간이다. 그리고 컴포넌트 스캔은 @Component 계열이 붙은 클래스를 찾아 Bean으로 등록하는 과정이다.

2일차의 DI와 연결해 보면 흐름이 분명해진다. 컴포넌트 스캔으로 클래스들이 Bean으로 등록되고, 그 Bean들이 서로 필요한 곳에 주입된다. 이 두 과정이 맞물려 Spring 애플리케이션이 동작한다.

다음 4일차에서는 지금까지 흩어져 등장한 핵심 어노테이션들을 한자리에 모아 정리한다. 각 어노테이션이 언제, 어떤 계층에서 쓰이는지 표로 깔끔하게 짚어 볼 것이다.

 

'Spring > Spring 기초 및 세팅' 카테고리의 다른 글

Spring day 4  (0) 2026.06.21
Spring day 2  (0) 2026.06.19
Spring day 1  (0) 2026.06.17