1. @Configuration과 싱글톤
[왜 sington이 안 깨질까?]
package hello.core;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@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. 테스트
package hello.core.singleton;
import hello.core.AppConfig;
import hello.core.member.MemberRepository;
import hello.core.member.MemberServiceImpl;
import hello.core.order.OrderService;
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.assertThat;
public class CofigurationSingtonTest {
@Test
void cofigurationTest(){
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("memberService = "+ memberRepository);
assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
}
}
3.@Configuration과 바이트코드 조작의 마법
- @Configuration을 적용한 AppConfig는 순수한 클래스가 스프링 컨테이너에 등록되는 것이 아닌 이를 부모로 상속 받은 AppConfigCGLIB가 나타나는 걸 볼 수 있다.
- 이는 AppConfig를 상속받은 AppConfigCGLIB가 스프링이 등록되어 있으면 스프링 컨테이너에서 찾아서 반환해주고 스프링 컨테이너에 @Bean이 붙은 메소드가 없다면 기존 로직을 호출해서 생성 후 스프링 컨테이너에 넣어 반환해줄 것이다.
- @Configuration 을 붙이면 바이트코드를 조작하는 CGLIB 기술을 사용해서 싱글톤을 보장하지만, 만약 @Bean만 적용하면 어떻게 될까
- 우리가 등록했던 순수한 자바 클래스가 나올 것이고 이때 싱글톤이 깨지게 될 것이다.
4. 정리
- @Bean만 사용해도 스프링 빈으로 등록되지만, 싱글톤을 보장하지 않는다.
- memberRepository() 처럼 의존관계 주입이 필요해서 메서드를 직접 호출할 때 싱글톤을 보장하지 않는다.
- 크게 고민할 것이 없다. 스프링 설정 정보는 항상 @Configuration 을 사용하자
5. 출처
'Back-End > Spring' 카테고리의 다른 글
[Spring][스프링 기본편] - 20. 의존관계 주입 (0) | 2022.01.28 |
---|---|
[Spring][스프링 기본편] - 19. 컴포넌트 스캔 (0) | 2022.01.27 |
[Spring][스프링 기본편] - 17. 싱글톤 방식의 주의점 (0) | 2022.01.26 |
[Spring][스프링 기본편] - 16. 싱글톤 컨테이너 (0) | 2022.01.26 |
[Spring][스프링 기본편] - 15. 싱글톤 패턴 적용과 테스트 그리고 수많은 문제점들 (0) | 2022.01.26 |