AppConfig 코드의 이상한 점이 있는데,
memberService() 호출시 memberRepository() 호출되어 new MemoryMemberRepository() 호출
orderService() 호출시 memberRepository() 호출되어 new MemoryMemberRepository() 호출
각각 다른 2개의 MemoryMemberRepository 생성되어 싱글톤 깨지는 것처럼 보인다.
스프링 컨테이너는 이 문제를 어떻게 해결할까?
1. 검증 용도의 코드 추가
각 서비스 구현체에 MemberRepository 를 조회할 수 있는 메서드를 임시로 추가한다.
- src/main/java/hello/core/member/MemberServiceImpl.java
...
// 테스트 용도
public MemberRepository getMemberRepository() {
return memberRepository;
}
...
- src/main/java/hello/core/order/OrderServiceImpl.java
...
// 테스트 용도
public MemberRepository getMemberRepository() {
return memberRepository;
}
...
2. 테스트 코드
- src/test/java/hello/core/singleton/ConfigurationSingletonTest.java
package hello.core.singleton;
import hello.core.AppConfig;
import hello.core.member.MemberRepository;
import hello.core.member.MemberServiceImpl;
import hello.core.order.OrderServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.assertj.core.api.Assertions.*;
class ConfigurationSingletonTest {
@Test
void configurationTest() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);
// 모두 같은 인스턴스를 참고하고 있다.
System.out.println("memberService -> memberRepository = " + memberService.getMemberRepository());
System.out.println("orderService -> memberRepository = " + orderService.getMemberRepository());
System.out.println("memberRepository = " + memberRepository);
// 모두 같은 인스턴스를 참고하고 있다.
assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
}
}
- 콘솔
memberService -> memberRepository = hello.core.member.MemoryMemberRepository@27e5b378
orderService -> memberRepository = hello.core.member.MemoryMemberRepository@27e5b378
memberRepository = hello.core.member.MemoryMemberRepository@27e5b378
MemberRepository 인스턴스는 모두 같은 인스턴스가 공유되어 사용된다.
하지만, AppConfig 의 자바 코드는 분명 각각 2번의 new MemoryMemberRepository() 호출해서 다른 인스턴스가 생성되어야 하는데 어떻게 된 일일까? 혹시 2번 호출이 안되는 것일까?
3. AppConfig에 호출 로그 남김
- src/main/java/hello/core/AppConfig.java
...
@Bean
public MemberService memberService() {
// 1번
System.out.println("call AppConfig.memberService");
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
// 1번
System.out.println("call AppConfig.orderService");
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
// 2번? 3번?
System.out.println("call AppConfig.memberRepository");
return new MemoryMemberRepository();
}
...
스프링 컨테이너가 각각 @Bean을 호출해서 스프링 빈을 생성하니 memberRepository() 는 총 3번 호출될 것이 기대된다.
1) 스프링 빈 등록하기 위해 @Bean 붙어있는 memberRepository() 호출
2) memberService() 에서 호출
3) orderService() 에서 호출
하지만, 출력 결과는 모두 1번만 호출된다.
- 콘솔
call AppConfig.memberService
call AppConfig.memberRepository
call AppConfig.orderService
@Configuration 은 싱글톤을 위해 존재!
참고링크 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8?cid=325969
스프링 핵심 원리 - 기본편| 김영한 - 인프런 강의
현재 평점 5.0점 수강생 49,552명인 강의를 만나보세요. 스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 스프링 기본 기능, 스프
www.inflearn.com
'강의 실습 > 스프링 핵심 원리 - 기본편' 카테고리의 다른 글
| 컴포넌트 스캔과 의존관계 자동 주입 시작하기 (0) | 2026.04.20 |
|---|---|
| @Configuration과 바이트코드 조작의 마법 (1) | 2026.04.18 |
| 싱글톤 방식의 주의점 (0) | 2026.04.17 |
| 싱글톤 컨테이너 (0) | 2026.04.15 |
| 싱글톤 패턴 (0) | 2026.04.14 |
댓글