본문으로 건너뛰기
안동민 개발노트 아이콘

안동민 개발노트

본문 시작
3장 : 컨테이너·빈·생명주기·스코프

빈 정의와 조회

빈 정의·빈 이름·타입 후보의 뜻을 PasswordHasher 구현으로 확인하고 단일 조회와 복수 조회의 차이를 구분합니다.

빈을 등록하면 컨테이너는 객체만 보관하는 것이 아니라 이름, 타입, 생성 방법, 스코프 같은 빈 정의도 관리합니다.

주입할 대상을 찾을 때는 이 정보로 후보를 고릅니다.


두 구현 등록

HasherConfig.java
@Configuration(proxyBeanMethods = false)
class HasherConfig {
    @Bean
    PasswordHasher testPasswordHasher() {
        return new TestPasswordHasher();
    }

    @Bean
    PasswordHasher pbkdf2PasswordHasher() {
        return new Pbkdf2PasswordHasher(settings());
    }
}

@Bean 메서드 이름이 기본 빈 이름이 됩니다.

두 메서드의 반환 타입은 같지만 실제 구현 클래스와 빈 이름은 다릅니다.


이름과 타입 조회

try (var context = new AnnotationConfigApplicationContext(
        HasherConfig.class)) {
    PasswordHasher byName = context.getBean(
            "testPasswordHasher", PasswordHasher.class);

    Map<String, PasswordHasher> all =
            context.getBeansOfType(PasswordHasher.class);

    assertThat(byName).isInstanceOf(TestPasswordHasher.class);
    assertThat(all).containsKeys(
            "testPasswordHasher", "pbkdf2PasswordHasher");
}

이름 조회는 지정한 한 빈을 찾고, 타입 복수 조회는 그 타입에 할당할 수 있는 모든 빈을 찾습니다.


단일 타입 조회 실패

assertThatThrownBy(() ->
        context.getBean(PasswordHasher.class))
        .isInstanceOf(NoUniqueBeanDefinitionException.class);

후보가 둘인데 하나만 요구하면 컨테이너가 임의로 고르지 않습니다.

어떤 구현이 기본인지, 어떤 구현을 특정 위치에서 써야 하는지 구성에 근거를 남겨야 합니다.


빈 이름은 업무 키가 아니다

getBeansOfType이 반환하는 맵의 키는 빈 이름입니다.

이를 HTTP 요청의 algorithm=pbkdf2PasswordHasher 같은 공개 계약으로 사용하면 구성 메서드 이름을 바꿀 때 API도 깨집니다.

외부에서 구현을 선택해야 한다면 PasswordAlgorithm.PBKDF2 같은 별도 업무 키와 허용 목록을 둡니다.


빈 정의와 인스턴스

구분의미
빈 정의클래스·팩토리·스코프객체를 어떻게 만들지
빈 이름pbkdf2PasswordHasher컨테이너 내부 식별자
빈 타입PasswordHasher주입 후보를 찾는 계약
빈 인스턴스Pbkdf2PasswordHasher 객체실제 호출 대상

클래스 하나로 빈을 둘 만들 수도 있고, 인터페이스 하나에 여러 구현 빈이 있을 수도 있습니다.

클래스 수와 빈 수를 같은 것으로 보지 않습니다.


연습 문제

같은 MemberRepository 타입으로 메모리와 JDBC 빈을 등록해 단일 조회 실패를 확인하세요.

테스트 환경에서는 메모리 구현만, 운영 환경에서는 JDBC 구현만 활성화하는 편이 두 빈을 항상 등록한 뒤 이름으로 고르는 방식보다 왜 단순한지도 설명합니다.