Backend/Spring

[스프링핵심원리 - 기본편]@Configuration과 싱글톤

seung_soos 2023. 3. 21. 12:02

Appconfig내에서

@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService(){
        return new MemberServiceImpl(memberRepository());
    }
    @Bean
    public OrderService orderService(){
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }
    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    @Bean
    public DiscountPolicy discountPolicy(){
        return new RateDiscountPolicy();
//        return new FixDiscountPolicy();
    }

}
  • memberService 빈을 만드는 코드를 보면 memberRepository()를 호출한다.
    • 이메서드를 호출하면 new MemberRepository()를 호출한다.
  • orderService 빈을 만드는 코드를 보면 memberRepository()를 호출한다.
    • 이메서드를 호출하면 new MemberRepository()를 호출한다.

결과적으로 각각 다른 2개의  new MemberRepository()가 생성되면서 싱글톤이 깨지는것처럼보인다.

 

Test 코드를 작성하여 확인

 

MemberServiceImpl

public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository;

    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
	}
	//테스트 용도
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}

OrderServiceImpl

public class OrderServiceImpl implements OrderService{

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
    //테스트 용도
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}
public class ConfigurationTest {

    @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("memberRepository = " + memberRepository);
        System.out.println("memberService -> memberRepository = " + memberRepository1);
        System.out.println("orderService -> memberRepository = " + memberRepository2);

        Assertions.assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
        Assertions.assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
    }

}

 

결과

memberRepository = hello.core.member.MemoryMemberRepository@95e33cc
memberService -> memberRepository = hello.core.member.MemoryMemberRepository@95e33cc
orderService -> memberRepository = hello.core.member.MemoryMemberRepository@95e33cc

 

확인결과 모든 memberRepository 인스턴스는 같은 객체를 가진다.

 

@Bean이 붙은 메서드마다 이미 스프링 빈이 존재하면 존재하는 빈을 반환하고, 스프링 빈이 없으면 생성해서 스프링 빈으로 등록하고 반홚나다.

 => 싱글톤이 보장된다.

 

AppCofig@CGLIB

순수한 클래스라면 'class.hello.core.AppCofig' 라고 출력이되어야 한다.

xxxCGLIB이 붙으면 내가만든 클래스가 아니라 스프링이 CGBLIB이라는 바이트 코드조작 라이브러리를 사용해서 AppConfig 클래스를 상속받은 임의의 다른 클랜스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한 것이다.

그 임의의 다른 클래스가 바로 싱글톤이 보장되도록해준다. 

 

※  @Configuration 을 적용하지않고 @Bean만적용시 스프링 빈 등록은 가능하다, 하지만 싱글톤 보장이 되지않는다.

      Spring 설정정보 Class에는 @Configuration을 항상 사용하자!

 

 

결과

memberRepository = hello.core.member.MemoryMemberRepository@74287ea3
memberService -> memberRepository = hello.core.member.MemoryMemberRepository@7d7758be
orderService -> memberRepository = hello.core.member.MemoryMemberRepository@2bdd8394

 

 

 

강의출처 : 스프링 핵심 원리 - 기본편 - 인프런 | 강의 (inflearn.com)