해당 글은,
https://velog.io/@dlsrjsdl6505/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88
에 이어져서 작성됩니다!~ :)
그럼, Spring은 순수자바 싱글톤 코드도 없으면서,
어떻게 자체적으로 Bean들을 싱글톤으로 제공할 수 있는걸까?
작성된 AppConfig는 다음과 같다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy(){
return new RateDiscountPolicy();
}
}
해당 코드를 보면,
음, orderService, memberService
둘 다 memberRepository
매서드를 사용하네.
근데 memberRepository
매서드는
return new MemoryMemberRepository();
인데,
oerderService, memberService
매서드를 사용할때마다
각각 new MemoryMemberRepository();
가 실행되어
싱글톤이 안되고 여러개의 MemoryMemberRepository
가 생기는게 아닐까?
라는 의문이 들 수 있다.
해당 의문 해소를 위해, orderService와 memberService에
해당 인스턴스의 memberRepository를 반환하는 매서드를 작성한 후,
//싱글톤 테스트용, memberService와 orderService 둘 다에 작성
public MemberRepository getMemberRepository() {
return this.memberRepository;
}
테스트코드를 작성했다.
@Test
@DisplayName("과연 스프링은 AppConfig에서 new로 여러번 생성되는 객체들도 싱글톤으로 관리할것인지..?")
void configuationTest(){
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
MemberRepository memberRepository1= memberService.getMemberRepository();
MemberRepository memberRepository2 = orderService.getMemberRepository();
System.out.println("memberService → memberServiceRepository = " + memberRepository1);
System.out.println("orderService → memberServiceRepository = " + memberRepository2);
//확인해보면 memberRepository 인스턴스는 모두 같은 인스턴스가 공유되어 사용된다.
}
결과는, 아래와 같다.
즉, memberService나 orderService나
return new MemortMemberReopository();
가 되어도,
똑같은 memberRepository를 갖게 되는 것이다.
뭐야, 어떻게 이럴 수 있지?
아래에 설명이 있다.
다시 위에서 AppConfig 클래스를 보고 오시면,
클래스단위에 @Configuration
어노테이션을 볼 수 있다.
답은 그곳에 있다!
스프링이 CGLIB라는 바이트코드 조작 라이브러리를 사용해서 @Configuration
이 붙은 AppConfig 클래스를 상속받은
임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한 것이다.
그림은 다음과 같다.
But,
해당 바이트코드 조작 내부 기술은 매우 복잡하다고 한다..ㅠㅠ
즉, 내부적으로
Spring이 @Configuration
이 붙은 클래스 차원에서
해당 클래스를 상속한 같은 클래스를 만들고,
그 같은 클래스 안에서는 기존의 클래스와 다르게
@Bean
이 붙은 스프링 빈들을 사용할 때
생성되어있으면 그대로 return,
생성되어있지 않으면 생성하고 컨테이너에 등록
이라는 로직이 동적으로 만들어져 장착된다.
라고 생각하면 되겠다.
ps.
스프링 프레임워크의 동작 방식도 뜯어보면 가끔 재밌다는 생각이 든다.
모르는것을 알아가는 즐거움인가..?
소스코드 : https://github.com/ingeon2/coreofspring-SOLID
레퍼런스 : 김영한님 pdf