memberRepository() -> new MemoryMemberRespository 객체를 새로 생성하는 메서드
1. memberService() -> memberRepository -> new MemoryMemberRespository 사용
2. orderService ()-> memberRepository -> new MemoryMemberRespository 사용
1번에서 사용되는 MemoryMemberRespository와 2번에서 사용된 MemoryMemberRespository는
서로 다른 객체이지 않을까? (둘다 메서드를 사용할 때 new 키워드로 새로 생성되기 때문에)
만약 다른 객체라면 싱글톤 패턴에 위배되는 현상!
[테스트 결과]
@Test
void configurationTest() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
MemoryMemberRepository memberRepository = ac.getBean("memberRepository", MemoryMemberRepository.class);
MemberRepository memberRepository1 = memberService.getMemberRepository();
MemberRepository memberRepository2 = orderService.getMemberRepository();
System.out.println("memberService = " + memberRepository1);
System.out.println("orderService = " + memberRepository2);
System.out.println("MemoryMemberRepository = " + memberRepository);
// memberService = hello.core.member.MemoryMemberRepository@333dd51e
// orderService = hello.core.member.MemoryMemberRepository@333dd51e
// MemoryMemberRepository = hello.core.member.MemoryMemberRepository@333dd51e
Assertions.assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
Assertions.assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
놀랍게도 모두 같은 객체
심지어 MemoryMemberRepository를 직접 호출한 객체조차 모두 같은 객체였다.
AppConfig에 호출할때마다 로그를 남겨 확인해본 결과
call AppConfig.memberRepository
call AppConfig.memberService
call AppConfig.orderService
각각의 객체를 한번씩만 호출했다.
그 이유는 아래에 설명
@Configuration과 바이트코드 조작
스프링 컨테이너는 싱글톤 레지스트리다. 따라서 스프링 빈이 싱글톤이 되도록 보장해주어야한다.
@Test
void configurationDeep() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
//bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$65898
}
순수한 클래스라면 class hello.core.AppConfig로 출력되어야 하는데 위와 같이 bean을 출력해보면
class hello.core.AppConfig$$EnhancerBySpringCGLIB$$65898라고 출력이된다.
이것은 내가 만든 클래스가 아니라 스프링이 CGLIB라는 바이트코드 조작 라이브러리를 사용해서 AppConfig 클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한 것이다.
즉, 내가 등록한 AppConfig는 사라지고 Spring이 직접 생성한 객체를 빈으로 등록하여 그 클래스를 사용하기 때문이다.
AppConfig@CGLIB (실제 사용) -> AppConfig
강의에서 추측하기로는
memoryMemberRepository가 이미 스프링 컨테이너에 등록되어 있으면, new 키워드를 사용하지 않고 스프링 컨테이너에서 찾아서 반환하고, 없으면 기존에 작성한 코드와 같이 객체를 생성하여 반환한다고 한다.
@Configuration을 적용하지 않고 @Bean만 적용하게 되면 아래와 같이
memberRepository를 매번 생성하게 된다.
즉, @Configuration은 싱글톤을 보장하도록 도와주는 애노테이션이다.
call AppConfig.memberRepository
call AppConfig.memberService
call AppConfig.memberRepository
call AppConfig.orderService
call AppConfig.memberRepository
memberService = hello.core.member.MemoryMemberRepository@535779e4
orderService = hello.core.member.MemoryMemberRepository@53fd0d10
MemoryMemberRepository = hello.core.member.MemoryMemberRepository@6c0d9d86
'SpringFramework > Spring 중요 개념' 카테고리의 다른 글
[Spring] 의존관계 자동 주입 (1) (0) | 2021.12.22 |
---|---|
[Spring] 컴포넌트 스캔 (0) | 2021.12.21 |
[Spring] 싱글톤 컨테이너 (0) | 2021.12.17 |
[Spring] 스프링 컨테이너 (0) | 2021.12.16 |
[Spring] 스프링으로 변환하기 (0) | 2021.12.15 |
댓글