2장 : 객체지향 설계와 Spring
Spring 컨테이너 전환
순수 Java BoardConfig와 같은 회원가입 객체 그래프를 Spring 빈으로 등록하고 타입 조회·생성자 주입·모호성 실패를 확인합니다.
Spring 컨테이너는 우리가 직접 작성한 BoardConfig와 같은 객체 조립을 일관되게 수행합니다.
빈은 컨테이너가 만들고 관리하는 객체이고, @Bean은 메서드 반환 객체를 빈으로 등록하라는 표시입니다.
빈 정의
@Configuration(proxyBeanMethods = false)
public class BoardConfig {
@Bean
MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
PasswordHasher passwordHasher() {
return new TestPasswordHasher();
}
@Bean
MemberRegistrationService memberRegistrationService(
MemberRepository members,
PasswordHasher passwordHasher
) {
return new DefaultMemberRegistrationService(
members, passwordHasher);
}
@Bean
LoginService loginService(
MemberRepository members,
PasswordHasher passwordHasher
) {
return new LoginService(members, passwordHasher);
}
}@Bean 메서드의 매개변수는 컨테이너가 타입으로 찾습니다.
두 서비스의 MemberRepository 매개변수에는 같은 싱글톤 빈이 전달됩니다.
컨테이너 실행
try (var context = new AnnotationConfigApplicationContext(
BoardConfig.class)) {
var registration = context.getBean(
MemberRegistrationService.class);
var login = context.getBean(LoginService.class);
Member member = registration.register(new SignUpCommand(
"member@example.com", "회원", "secret-1234"));
long loginId = login.authenticate(
"member@example.com", "secret-1234");
System.out.println(member.id() == loginId);
}getBean은 학습과 기반 코드에서 컨테이너를 관찰하기 위한 API입니다.
일반 컨트롤러는 컨테이너를 직접 조회하지 않고 생성자로 필요한 서비스를 받습니다.
빠르게 실패하는 구성
MemberRepository 빈이 없으면 컨테이너는 MemberRegistrationService를 만들 수 없으므로 시작 중 실패합니다.
후보가 두 개인데 선택 기준이 없어도 실패합니다.
요청을 받은 뒤 null 오류가 나는 것보다 설정 단계에서 원인을 드러내는 편이 안전합니다.
No qualifying bean of type 'MemberRepository' available수동 구성과 Spring 구성 비교
| 항목 | 순수 Java 구성 | Spring 구성 |
|---|---|---|
| 역할·구현 설계 | 개발자가 작성 | 동일 |
| 객체 생성 | new와 필드 | @Bean 메서드 |
| 의존성 연결 | 생성자 직접 호출 | 타입 기반 매개변수 주입 |
| 공유 수명 | 구성 객체가 관리 | 컨테이너가 관리 |
Spring이 나쁜 객체 설계를 자동으로 고쳐 주지는 않습니다. 먼저 역할을 나눈 뒤 조립을 맡길 때 의미가 있습니다.