자바 백엔드 입문 16편 — Bean이란 일반 객체와의 차이

2026-05-16자바 백엔드 입문

자바 백엔드 입문 16편. Spring Bean이 일반 자바 객체와 어떻게 다른지, BeanDefinition·생명주기·이름 규칙을 도서관 책 비유로 풀어쓴 학습 노트.

📚 자바 백엔드 입문 · 16편 — Bean이란 일반 객체와의 차이

이 글은 자바 백엔드 입문 시리즈 59편 중 16편이에요. 15편에서 의존성 주입이 왜 필요한가를 풀었다면, 이번 16편은 그 의존성 주입의 대상인 Bean을 깊이 들여다봅니다. 14편에서 짧게 만난 Bean을 본격적으로 풀어 가요.

Bean이 어렵게 들리는 이유

처음 "Bean" 이라는 단어를 들으면 두 가지가 안 잡혀요.

첫째, 이름 자체가 모호해요. "커피 빈?", "자바 빈?". "왜 객체를 Bean이라고 부르는지" 가 단어 자체로는 안 보입니다.

둘째, 일반 자바 객체와 어떻게 다른지 가 안 잡혀요. "내가 new 로 만들면 객체, Spring이 만들면 Bean?" — 그럼 본질은 같은 것인가? 다른 것인가?

이 글에서는 Bean = 도서관 책 비유로 풀어 갑니다. 끝까지 따라오시면 "왜 Spring이 객체를 Bean이라는 별명으로 부르는지" 가 한 번에 박혀요.

Bean = 도서관 책 — 라이브러리 시스템이 관리

Spring Bean"Spring 컨테이너가 만들고, 보관하고, 필요할 때 꺼내주는 객체" 예요. 일반 자바 객체와 다른 점은 한 줄이에요 — 생명주기 책임이 우리에게 없고 컨테이너에 있다.

비유로 풀어볼게요. Spring Bean = 도서관 책. 책 자체는 그냥 종이 묶음이지만, "도서관 시스템에 등록" 되는 순간 의미가 달라져요. 일반 책은 본인이 가지고 다니고 분실해도 본인 책임. 도서관 책은 — 누가 만들었는지(출판사) 도서관 시스템이 알고, 어느 책장에 꽂혀 있는지 알고, 누가 빌렸는지 추적해주고, 똑같은 책을 두 권 살지 한 권 살지 정책을 정해줍니다.

자바 객체도 똑같아요. new Player() 로 만든 객체 = 일반 책. @Component 박힌 클래스로 Spring이 자동 생성한 객체 = 도서관 책(Bean). 같은 자바 객체지만 "누가 관리하는가" 의 시스템이 완전히 달라요.

BeanDefinition — Bean의 신분증

Spring 컨테이너 안에서 Bean은 단순히 객체 한 개로만 보관되지 않아요. BeanDefinition 이라는 메타데이터와 함께 보관돼요. 이게 도서관 책의 "바코드 + 카탈로그 정보" 같은 거예요.

Spring 공식 문서를 보면 BeanDefinition에 다음 정보가 들어 있어요.

속성 의미
Class 어느 자바 클래스로 만든 Bean인지 (예: com.example.HelloController)
Name Bean의 고유 이름 (기본: 클래스 이름 첫 글자 소문자, helloController)
Scope Singleton인지 Prototype인지 (한 권만 vs 여러 권)
Constructor arguments 생성자에 어떤 의존성 주입할지
Properties 세터로 어떤 값 설정할지
Autowiring mode 의존성 자동 주입 방식
Lazy init 시작 시 만들지, 첫 호출 때 만들지
Init method 객체 생성 직후 호출할 메서드 (@PostConstruct)
Destroy method 객체 폐기 직전 호출할 메서드 (@PreDestroy)

이 9개 속성이 Bean의 "신분증" 이에요. 우리가 @Component 한 줄만 박아도, Spring이 시작 시점에 이 9개 속성을 다 채워 BeanDefinition을 만들어 컨테이너에 보관합니다. 그러니까 Bean은 "객체 + 그 객체에 대한 메타데이터" 한 세트로 다뤄져요.

💡 BeanDefinition을 직접 만질 일은 거의 없어요

대부분의 입문자는 BeanDefinition 클래스를 직접 코드로 만질 일이 없어요. @Component 한 줄이 알아서 다 만들어줍니다. 다만 "Spring 안에서 Bean이 어떻게 보관되는지" 의 모델을 알아두면 14·15편 Bean Scope·Lifecycle이 한 번에 풀려요.

Bean 이름 규칙 — 작명 컨벤션

@Component 박은 클래스로 Bean이 만들어질 때, Bean 이름은 클래스 이름의 첫 글자를 소문자로 바꾼 게 기본이에요.

클래스 이름 자동 Bean 이름
HelloController helloController
OrderService orderService
UserRepository userRepository
URLParser (특수 케이스 — 앞 두 글자 대문자) URLParser (그대로)

마지막 케이스가 함정이에요. "앞 두 글자 모두 대문자" 인 경우는 원본 표기를 그대로 유지해요(예: URLParser·PDFGenerator). 이건 자바 java.beans.Introspector.decapitalize 룰을 따른 결과예요. 일반적인 작명은 PascalCase 클래스명에 대해 그냥 첫 글자만 소문자로 — 직관과 일치합니다.

원한다면 직접 이름을 줄 수도 있어요.

@Component("myCustomName")
public class HelloController { ... }

이러면 Bean 이름이 myCustomName 으로 등록돼요. 다른 곳에서 @Autowired 할 때 이 이름으로 지정 가능.

Alias — 같은 Bean에 별명 여러 개

한 Bean에 "별명" 을 더 박을 수도 있어요. Alias 라고 부르는데, 대형 시스템에서 "여러 부서가 같은 Bean을 자기 이름으로 부르고 싶을 때" 쓰여요.

@Component
@Bean(name = {"primaryName", "alias1", "alias2"})
public class OrderService { ... }

이 경우 primaryName·alias1·alias2 어느 이름으로 호출해도 같은 Bean이 반환돼요. 한 사람을 회사에서는 "김 과장", 가족에서는 "오빠", 친구가 "민철" 이라 부르는 것과 같은 그림이에요.

Bean의 정체성 — 같은 클래스라도 인스턴스는 한 개

여기서 가장 중요한 룰이 하나 있어요. 같은 클래스로 만들어진 Bean은 기본적으로 컨테이너 안에 한 개만 존재합니다. 이걸 Singleton Scope 라고 부르고, 14편에서 깊이 다뤄요.

@Component
public class HelloController { }

// Spring 컨테이너 안에는 HelloController 객체가 단 한 개만 존재
HelloController c1 = context.getBean(HelloController.class);
HelloController c2 = context.getBean(HelloController.class);
// c1 == c2  →  true (같은 객체)

여기서 시험 함정 자주 나와요. "Bean은 항상 Singleton이다" 가 보기로 나오면 X. 기본값은 Singleton이지만 @Scope("prototype") 같은 어노테이션으로 "매번 새 객체" 로 바꿀 수 있어요. Singleton은 "기본값" 이지 "강제" 가 아닙니다.

Bean의 생명주기 미리보기 — 5단계

15편에서 깊이 다루지만, 지금 짧게 미리보기 해둘게요. Bean 한 개는 다음 5단계를 거쳐요.

[1] 인스턴스화         (new로 객체 생성)
    ↓
[2] 의존성 주입        (다른 Bean들이 끼워 들어감)
    ↓
[3] 초기화 콜백        (@PostConstruct 실행)
    ↓
[4] 사용              (애플리케이션 동작 중)
    ↓
[5] 소멸 콜백          (@PreDestroy 실행, 컨테이너 종료 시)

Spring이 이 5단계를 다 알아서 처리해줘요. 우리가 new 도 안 하고, "의존성 끼워 넣기" 도 안 하고, "객체 폐기" 도 안 합니다. 컨테이너가 다 책임지는 거예요.

🎯 일반 객체 vs Bean 한 줄 비교

일반 객체 — 우리가 new로 만들고 우리가 책임짐. Bean — Spring이 만들고 Spring이 책임짐. 같은 자바 객체지만 "누가 관리하는가" 의 시스템이 완전히 다름.

한 줄 정리 — Bean = Spring 컨테이너가 만들고 관리하는 객체 + 그 객체의 메타데이터(BeanDefinition). 같은 클래스의 Bean은 기본적으로 컨테이너 안에 한 개(Singleton).

시험 직전 한 번 더 — Bean 입문자가 매번 헷갈리는 것

  • Bean = Spring 컨테이너가 만들고 관리하는 객체
  • 일반 객체와 다른 점 = 생명주기 책임이 컨테이너에 있음
  • 비유 = Bean은 도서관 책. 라이브러리 시스템이 등록·보관·대출 관리
  • BeanDefinition = Bean의 메타데이터. Class·Name·Scope·의존성·생명주기 콜백 등 9개 속성
  • Bean 이름 기본 = 클래스명 첫 글자 소문자 (HelloControllerhelloController)
  • 앞 두 글자 모두 대문자면 원본 유지 (URLParserURLParser)
  • @Component("customName") 으로 직접 이름 지정 가능
  • Alias = Bean 별명. 한 Bean에 여러 이름 부여 가능
  • Singleton Scope (기본) — 한 클래스의 Bean은 컨테이너 안에 1개
  • context.getBean(...) 으로 여러 번 받아도 같은 객체 반환
  • "Bean은 항상 Singleton" 은 X — @Scope("prototype") 으로 매번 새 객체 가능
  • Bean 생명주기 5단계 = 인스턴스화 → DI → 초기화 콜백 → 사용 → 소멸 콜백
  • @PostConstruct = 초기화 콜백, @PreDestroy = 소멸 콜백
  • Spring 컨테이너가 5단계 다 자동 처리 — 우리가 new 안 함
  • Bean 등록 = @Component·@Service·@Repository·@Controller·@RestController
  • 13편에서 다룰 @Bean 메서드도 Bean 등록 방법
  • 같은 클래스라도 Bean 이름이 다르면 서로 다른 Bean으로 인식
  • 컨테이너 안 Bean 목록 = context.getBeanDefinitionNames() 로 조회 가능
  • Spring Boot는 시작 시 기본적으로 수십~수백 개의 자동 Bean 등록
  • "Bean을 직접 만드는 것" 보다 "Bean을 어떻게 찾고 어떻게 끼워 넣는가" 가 입문자의 일반 작업

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!