빈 정의와 조회
빈 정의·빈 이름·타입 후보의 뜻을 PasswordHasher 구현으로 확인하고 단일 조회와 복수 조회의 차이를 구분합니다.
빈을 등록하면 컨테이너는 객체만 보관하는 것이 아니라 이름, 타입, 생성 방법, 스코프 같은 빈 정의도 관리합니다.
주입할 대상을 찾을 때는 이 정보로 후보를 고릅니다.
두 구현 등록
@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 구현만 활성화하는 편이 두 빈을 항상 등록한 뒤 이름으로 고르는 방식보다 왜 단순한지도 설명합니다.