ABOUT

성능과 운영 안정성을 함께 끌어올리는 개발자입니다.

92% Positional Error Reduction
79% p95 Latency Improvement
90%+ Long Tasks Reduction

2022.02 · 한국장학재단

우수 멘티

한국장학재단 사회 리더 대학생 멘토링 IT

2022.10 · 동작구청

우수 인재상

동작구청 우수 SW 인재

2025.05 · (주) 그랩

프로그래밍 우수상

(주) 그랩 우수 프로그램 개발

2025.05 · AWSKRUG

AWS한국사용자모임 발표

AI agent 스크립트 튜닝 관련 발표

ComputerScience

Development

Engineering

Trouble Shooting

GUESTBOOK

첫 마음부터
함께 나누는 온기

방명록 작성하러 가기

SUBSCRIBE

최신소식을
편하게 만나보세요.

bean

도입

Bean은 스프링 컨테이너가 생성하고 관리하는 객체다

스프링을 이해할 때 가장 먼저 정확히 잡아야 하는 개념이 바로 Bean입니다. 많은 입문자가 Bean을 단순히 “객체”라고 외우지만, 엄밀히 말하면 Bean은 스프링 컨테이너가 생성·보관·주입·생명주기 관리까지 담당하는 객체를 뜻합니다.

즉, 모든 객체가 Bean은 아닙니다. 자바에서 new로 직접 만든 객체는 그냥 일반 객체이고, 스프링 컨테이너 안에 등록되어 관리되는 객체만 Bean이라고 부릅니다.

정의

Bean은 “컨테이너가 관리하는 애플리케이션 구성요소”다

스프링에서 Bean은 단순히 메모리에 존재하는 인스턴스가 아니라, ApplicationContext(스프링 컨테이너)에 등록되어 관리되는 단위입니다. 컨테이너는 Bean의 생성 시점, 의존성 연결, 초기화, 소멸, 프록시 적용 여부까지 제어할 수 있습니다.

핵심 요약
  • Bean은 스프링 컨테이너가 관리하는 객체다.
  • Bean은 단순 객체와 달리 생명주기와 의존성 주입의 대상이 된다.
  • Bean은 애플리케이션의 기능을 구성하는 기본 조립 단위다.
TIP
“객체 = Bean”이 아닙니다. 컨테이너가 관리하면 Bean, 그렇지 않으면 그냥 객체입니다.

필요성

Bean은 객체 생성과 의존성 연결을 자동화해 애플리케이션 구조를 단순하게 만든다

Bean이 중요한 이유는 개발자가 직접 객체를 만들고 연결하는 부담을 줄여주기 때문입니다. 예전 방식처럼 클래스 안에서 다른 클래스를 new로 직접 생성하면 결합도가 높아지고, 테스트도 어려워집니다. 반면 스프링은 Bean을 통해 객체 생성 책임을 컨테이너로 넘기고, 필요한 의존성을 자동으로 주입합니다.

Bean이 중요한 이유
  • 객체 생성 책임 분리: 개발자가 직접 생성하지 않아도 된다.
  • 의존성 주입 지원: 필요한 객체를 자동 연결할 수 있다.
  • 유지보수성 향상: 클래스 간 결합도를 낮출 수 있다.
  • 테스트 용이성 증가: Mock 객체나 대체 구현체로 교체하기 쉽다.
  • 생명주기 제어: 초기화/소멸 시점을 컨테이너가 관리한다.

일반 객체와 차이

Bean은 “그냥 만든 객체”가 아니라 “컨테이너 안에서 관리되는 객체”다
구분 일반 객체 Spring Bean
생성 주체 개발자 스프링 컨테이너
의존성 연결 직접 연결 자동 주입 가능
생명주기 직접 관리 컨테이너가 관리
AOP 적용 어려움 프록시 적용 가능
public class UserService {
  private final UserRepository userRepository = new UserRepository();
}

위 코드는 UserRepository를 직접 생성하므로 일반 객체 사용 방식입니다. 반면 아래는 Bean을 주입받는 구조입니다.

@Service
public class UserService {
  private final UserRepository userRepository;

  public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
  }
}

등록 방식

Bean은 @Component 계열 또는 @Bean 메서드로 등록하는 것이 핵심이다
1. 컴포넌트 스캔 방식
import org.springframework.stereotype.Component;

@Component
public class MailSender { }

@Component, @Service, @Repository, @Controller 같은 어노테이션이 붙은 클래스는 컴포넌트 스캔 대상이 되고, 컨테이너에 Bean으로 등록됩니다.

2. 수동 등록 방식
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

  @Bean
  public MailSender mailSender() {
    return new MailSender();
  }
}

외부 라이브러리 객체나 생성 로직을 직접 제어해야 하는 경우에는 @Bean으로 수동 등록하는 방식이 자주 쓰입니다.

핵심 구분
내부 애플리케이션 클래스는 보통 @Component 계열, 외부 객체나 생성 제어가 필요한 경우는 @Bean이 자연스럽습니다.

생성·초기화·소멸

Bean은 등록만 되는 것이 아니라 일정한 생명주기 규칙에 따라 관리된다

Bean은 등록된 뒤 끝나는 것이 아니라, 컨테이너 안에서 다음 순서로 관리됩니다.

  1. Bean 정의 등록: BeanDefinition이 컨테이너에 저장된다.
  2. 인스턴스 생성: 스프링이 객체를 만든다.
  3. 의존성 주입: 생성자/필드/세터를 통해 다른 Bean을 연결한다.
  4. 초기화 콜백: @PostConstruct 등이 실행될 수 있다.
  5. 사용: 애플리케이션이 Bean을 활용한다.
  6. 소멸 콜백: 컨텍스트 종료 시 @PreDestroy 등이 호출될 수 있다.
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Component;

@Component
public class ConnectionManager {

  @PostConstruct
  public void init() {
    System.out.println("초기화");
  }

  @PreDestroy
  public void close() {
    System.out.println("종료");
  }
}

스코프

Bean은 기본적으로 Singleton이며, 필요에 따라 다른 스코프를 가질 수 있다

스프링 Bean의 기본 스코프는 singleton입니다. 즉, 같은 Bean 정의에 대해 보통 하나의 인스턴스만 생성되어 여러 곳에서 공유됩니다.

스코프 설명
singleton 기본값, 컨테이너당 하나의 인스턴스
prototype 요청할 때마다 새 객체 생성
request HTTP 요청마다 하나의 Bean
session HTTP 세션마다 하나의 Bean
실무 포인트
싱글톤 Bean은 여러 요청이 함께 쓰므로 상태를 내부에 저장하지 않는 설계가 매우 중요합니다.

의존성 주입과 관계

Bean은 DI의 대상이자 DI를 가능하게 만드는 재료다

의존성 주입은 결국 “어떤 객체가 다른 객체를 필요로 할 때, 그 객체를 스프링이 대신 넣어주는 것”입니다. 이때 주입 대상도 Bean이어야 하고, 주입해주는 객체도 Bean이어야 합니다. 그래서 Bean 개념을 이해하지 못하면 DI도 정확히 이해하기 어렵습니다.

@Repository
public class UserRepository { }

@Service
public class UserService {
  private final UserRepository userRepository;

  public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
  }
}

위 코드에서 UserRepositoryUserService 모두 Bean이며, 스프링은 UserService를 생성할 때 필요한 UserRepository Bean을 자동으로 주입합니다.

@Component와의 관계

@Component는 Bean을 등록하기 위한 대표적인 방법이지, Bean 그 자체는 아니다

이 부분은 입문자들이 자주 헷갈립니다. Bean은 결과이고, @Component는 그 결과를 만들기 위한 등록 수단 중 하나입니다.

개념 의미
Bean 스프링 컨테이너가 관리하는 객체
@Component 클래스를 Bean으로 등록하기 위한 어노테이션
@Bean 메서드 반환 객체를 Bean으로 등록하는 방식
한 줄 정리
@Component를 붙여서 Bean이 되는 것이지, Bean과 @Component가 같은 말은 아닙니다.

자주 하는 오해

Bean은 많다고 좋은 것이 아니라, 역할이 명확할수록 좋다
  • 오해 1: 모든 클래스를 Bean으로 만들어야 한다 → 아니다. 관리할 필요가 있는 구성요소만 Bean으로 둔다.
  • 오해 2: Bean이면 무조건 싱글톤이 안전하다 → 아니다. 상태를 가지면 동시성 문제가 생길 수 있다.
  • 오해 3: @Component와 Bean은 같은 말이다 → 아니다. 하나는 등록 수단, 하나는 관리 결과다.
  • 오해 4: 필드 주입이 가장 편하니 가장 좋다 → 아니다. 실무에서는 생성자 주입이 더 권장된다.

디버깅

Bean 관련 문제는 “등록 여부, 주입 여부, 충돌 여부” 순서로 보면 빠르다
1
해당 클래스가 정말 Bean으로 등록되었는지 확인한다.
2
패키지 스캔 범위에서 빠진 것은 아닌지 확인한다.
3
같은 타입 Bean이 여러 개여서 NoUniqueBeanDefinitionException이 난 것은 아닌지 확인한다.
4
Bean 이름 충돌이나 @Qualifier / @Primary 누락 여부를 확인한다.
5
등록은 됐는데 기능이 안 되면 AOP 프록시나 생명주기 문제를 의심한다.

요약

Bean을 이해하면 스프링의 IoC, DI, 생명주기, AOP가 한 번에 연결된다
  • ✅ Bean은 스프링 컨테이너가 관리하는 객체다.
  • ✅ 모든 객체가 Bean은 아니며, 등록된 객체만 Bean이다.
  • ✅ Bean은 DI의 대상이며 애플리케이션 조립의 기본 단위다.
  • ✅ @Component와 @Bean은 Bean 등록 방식이고, Bean은 그 결과물이다.
  • ✅ Bean의 기본 스코프는 singleton이며 상태 관리에 주의해야 한다.
728x90