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

안동민 개발노트

본문 시작
2장 : 객체지향 설계와 Spring

객체 공유와 구현 교체

회원가입·로그인 서비스가 같은 저장소를 공유해야 하는 이유를 확인하고 구현 교체의 변경 범위를 BoardConfig로 제한합니다.

구성 메서드가 호출될 때마다 새 메모리 저장소를 만들면 회원가입 서비스가 저장한 회원을 로그인 서비스가 찾지 못합니다. 클래스가 같아도 인스턴스가 다르면 내부 Map도 다릅니다.


실패하는 구성

MemberRepository memberRepository() {
    return new MemoryMemberRepository();
}

MemberRegistrationService memberRegistrationService() {
    return new DefaultMemberRegistrationService(
            memberRepository(), passwordHasher());
}

LoginService loginService() {
    return new LoginService(memberRepository(), passwordHasher());
}

두 서비스가 서로 다른 MemoryMemberRepository를 받습니다. 회원가입은 성공하지만 로그인은 회원을 찾지 못합니다.

한 인스턴스 공유

BoardConfig.java
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);
    }
}

공유해야 하는 상태의 소유자를 구성 루트가 명시합니다. 모든 객체를 무조건 하나만 만들라는 뜻은 아닙니다. 요청마다 달라야 하는 입력 객체는 매번 만들고, 애플리케이션 전체에서 같은 저장 상태를 봐야 하는 저장소는 공유합니다.

해시 구현 교체

운영 환경에서는 구성 코드 한 곳에서 구현을 바꿉니다.

 private final PasswordHasher passwordHasher =
-        new TestPasswordHasher();
+        new Pbkdf2PasswordHasher(passwordSettings);

DefaultMemberRegistrationService, LoginService, MemberRepository는 바뀌지 않습니다. 테스트용 구성은 계속 빠른 가짜 구현을 사용할 수 있습니다.

공유 여부 판단

대상보통의 수명이유
저장소·서비스애플리케이션 동안 공유상태와 설정을 일관되게 사용
가입 요청 DTO요청마다 새로 생성사용자 입력이 서로 다름
로그인 세션로그인마다 생성사용자별 인증 상태

Spring에서는 이런 수명을 스코프라고 부릅니다. 3장에서 싱글톤, 프로토타입, 요청 스코프를 정의부터 배웁니다.

연습 문제

회원가입과 로그인 서비스가 같은 PasswordHasher를 받는지 기록하는 가짜 구현으로 검증하세요. 서로 다른 해시 구현을 받으면 어떤 로그인 실패가 생기는지도 설명합니다.