객체 공유와 구현 교체
회원가입·로그인 서비스가 같은 저장소를 공유해야 하는 이유를 확인하고 구현 교체의 변경 범위를 BoardConfig로 제한합니다.
구성 메서드가 호출될 때마다 새 메모리 저장소를 만들면 회원가입 서비스가 저장한 회원을 로그인 서비스가 찾지 못합니다.
클래스가 같아도 인스턴스가 다르면 내부 Map도 다릅니다.
Test 구현에서 PBKDF2 구현으로 바꿀 때 서비스와 테스트 코드는 그대로여야 한다.
- 고정 역할
PasswordHasher 계약
- Test config
FastHasher 선택
- Prod config
BCryptHasher 선택
- 영향 범위
구성 파일 한곳만 변경
실패하는 구성
MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
MemberRegistrationService memberRegistrationService() {
return new DefaultMemberRegistrationService(
memberRepository(), passwordHasher());
}
LoginService loginService() {
return new LoginService(memberRepository(), passwordHasher());
}두 서비스가 서로 다른 MemoryMemberRepository를 받습니다.
회원가입은 성공하지만 로그인은 회원을 찾지 못합니다.
한 인스턴스 공유
public final class BoardConfig {
private final MemberRepository members =
new MemoryMemberRepository();
private final PasswordHasher passwordHasher =
new TestPasswordHasher();
public MemberRegistrationService memberRegistrationService() {
return new DefaultMemberRegistrationService(
members, passwordHasher);
}
public LoginService loginService() {
return new LoginService(members, passwordHasher);
}
}공유해야 하는 상태의 소유자를 구성 루트가 명시합니다.
모든 객체를 무조건 하나만 만들라는 뜻은 아닙니다.
요청마다 달라야 하는 입력 객체는 매번 만들고, 애플리케이션 전체에서 같은 저장 상태를 봐야 하는 저장소는 공유합니다.
서비스마다 저장소를 새로 만들면 같은 애플리케이션 안에 서로 다른 메모리 상태가 생긴다.
- Repository
공유 상태를 입력
- Hasher
선택한 정책을 입력
- Service
완성된 객체 반환
- Consumers
controller·batch가 재사용
해시 구현 교체
운영 환경에서는 구성 코드 한 곳에서 구현을 바꿉니다.
private final PasswordHasher passwordHasher =
- new TestPasswordHasher();
+ new Pbkdf2PasswordHasher(passwordSettings);DefaultMemberRegistrationService, LoginService, MemberRepository는 바뀌지 않습니다.
테스트용 구성은 계속 빠른 가짜 구현을 사용할 수 있습니다.
정책 추가, 구현 선택, 서비스 책임을 각각 분리하면 변경이 올바른 경로로만 흐른다.
| 원칙 | 적용 지점 | 검증 질문 |
|---|---|---|
| OCP | 새 정책 구현 추가 | 기존 서비스 수정이 없는가 |
| DIP | 서비스의 역할 의존 | 구체 타입을 import하지 않는가 |
| SRP | Config와 Service 분리 | 변경 이유가 하나인가 |
공유 여부 판단
| 대상 | 보통의 수명 | 이유 |
|---|---|---|
| 저장소·서비스 | 애플리케이션 동안 공유 | 상태와 설정을 일관되게 사용 |
| 가입 요청 DTO | 요청마다 새로 생성 | 사용자 입력이 서로 다름 |
| 로그인 세션 | 로그인마다 생성 | 사용자별 인증 상태 |
Spring에서는 이런 수명을 스코프라고 부릅니다.
3장에서 싱글톤, 프로토타입, 요청 스코프를 정의부터 배웁니다.
회원가입과 로그인은 같은 저장소와 PasswordHasher 인스턴스를 공유한다.
- Repository
instance 한 번 생성
- Write service
같은 참조 주입
- Read service
같은 참조 주입
- Identity check
두 service의 저장소 동일
연습 문제
회원가입과 로그인 서비스가 같은 PasswordHasher를 받는지 기록하는 가짜 구현으로 검증하세요.
서로 다른 해시 구현을 받으면 어떤 로그인 실패가 생기는지도 설명합니다.