Spring 기본편
@Configuration과 싱글톤
J-Chris
2023. 3. 22. 06:45
사실 @Configuration은 싱글톤 때문에 있는 것이다.
다음 AppConfig 코드를 보자. (이상한 것이 있다)
public class AppConfig {
// @Bean memberService --> new MemoryMemberRepository()
// @Bean orderService --> new MemoryMemberRepository()
@Bean
public MemberService memberService() {
return new MemberServiceImpl(new memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(
memberRepository(),
discountPolicy());
}
...
}
- memberService 빈을 만드는 코드를 보면 memberRepository()를 호출한다.
- 이 메서드를 호출하면 new MemoryMemberRepository()를 호출한다.
- orderService 빈을 만드는 코드도 동일하게 memberRepository()를 호출한다.
- 이 메서드를 호출하면 new MemoryMemberRepository()를 호출한다.
결과적으로 각각 다른 2개의 MemoryMemberRepository가 생성되면서 싱글톤이 꺠지는 것처럼 보인다.
스프링 컨테이너는 이 문제를 어떻게 해결할까 ?
직접 테스트 해보자.
`검증 용도의 코드 추가`
public 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);
MemberRepository memberRepository1 = memberService.getMemberRepository();
MemberRepository memberRepository2 = orderService.getMemberRepository();
System.out.println("memberService -> memberRepository = " + memberRepository1);
System.out.println("orderService -> memberRepository = " + memberRepository2);
System.out.println("memberRepository = " + memberRepository);
assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
}
}
- 확인해보면 memberRepository 인스턴스는 모두 같은 인스턴스가 공유되어 사용된다
- AppConfig의 자바 코드를 보면 분명히 각각 2번 new MemoryMemberRepository를 호출해서 다른 인스턴스가 생성되어야 하는데?
- 어떻게 된 일일까 ? 혹시 두번 호출이 안되는 것일까 ?
스프링 컨테이너가 @Bean을 호출해서 스프링 빈을 생성한다. 그래서 memberRepository()는 다음과 같이
총 3번이 호출되어야 하는 것 아닐까?
- 1. 스프링 컨테이너가 스프링 빈에 등록하기 위해 @Bean이 붙어있는 memberRepository() 호출
- 2. memberService() 로직에서 memberRepository() 호출
- 3. orderService() 로직에서 memberRepository() 호출
그런데 출력 결과는 모두 1번만 호출된다.
call AppConfig.memberSerivce
call AppConfig.memberRepository
call AppConfig.orderService