-
(스프링 기본) 16 - @Configuration과 싱글톤 (바이트코드 조작)개발/Spring 2024. 10. 24. 13:47
//@Configuration @Configuration public class AppConfig { //@Bean memberService -> MemoryMemberRepository() //@Bean orderService -> MemoryMemberRepository() @Bean public MemberService memberService() { return new MemberServiceImpl(memberRepository()); } @Bean public MemberRepository memberRepository() { return new MemoryMemberRepository(); } @Bean public OrderService orderService() { return new OrderServiceImpl(memberRepository(), discountPolicy()); } @Bean public DiscountPolicy discountPolicy() { // return new FixDiscountPolicy(); return new RateDiscountPolicy(); }
@Bean memberService -> MemoryMemberRepository()
@Bean orderService -> MemoryMemberRepository()
이렇게 두 개 모두 MemoryMemberRepository()를 호출하여
각각 2개의 다른 객체가 생성돼 싱글톤이 깨지는 것처럼 보인다.
@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(memberRepository1).isSameAs(memberRepository2); assertThat(memberRepository1).isSameAs(memberRepository); }
그러나 결과적으로는 모두 같은 객체를 보고 있다.
■ 바이트코드 조작
@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$$SpringCGLIB$$0
이렇게 하면 AppConfig 도 bean 으로 등록이 된다.
출력해보면 다음과 같이 CGLIB 가 붙은 형태로 출력된다.
스프링이 CGLIB 라는 바이트코드 조작 라이브러리를 사용해서 AppConfig 클래스를 상속받은
임의의 다른 클래스를 만들고 그 다른 클래스를 스프링 빈으로 등록한 것이다.
이 임의의 다른 클래스가 바이트코드를 조작해서 싱글톤이 보장되도록 한다.
만약 이미 등록되어 있으면 찾아서 반환하고,
그렇지 않다면 기존 로직 호출해서 생성하고 스프링 컨테이너에 등록해서 반환한다.
■ 정리
- @Bean 만 사용해도 스프링 빈으로 등록되지만, 싱글톤 보장은 하지 않는다.
- memberRepository() 처럼 의존관계 주입이 필요해서 메서드를 직접 호출할 때 싱글톤을 보장하지 않는다.
- 스프링 설정 정보는 항상 @Configuration 사용하면 된다.
즉, 스프링 설정 정보에 @Bean을 통해 스프링 빈으로 등록하고,
@Configuration 을 붙여주게 되면 자동으로 스프링 컨테이너가 호출에 상관 없이 싱글톤을 유지해주는 것이다.
출처 : 김영한 스프링 핵심 원리 - 기본편
'개발 > Spring' 카테고리의 다른 글
(스프링 기본) 18 - 다양한 의존관계 주입 방법 (생성자, 수정자, 필드, 일반 메서드) (0) 2024.10.28 (스프링 기본) 17 - 컴포넌트 스캔 (0) 2024.10.24 (스프링 기본) 15 - 싱글톤 방식의 주의점 (공유필드) (0) 2024.10.24 (스프링 기본) 14 - 싱글톤 컨테이너 (0) 2024.10.24 (스프링 기본) 13 - 싱글톤 패턴 (0) 2024.10.23