minOS

싱글톤 컨테이너(3) - @Configuration과 싱글톤 본문

TIL/김영한의 스프링 핵심 원리

싱글톤 컨테이너(3) - @Configuration과 싱글톤

minOE 2024. 3. 13. 15:10
728x90

AppConfig코드

@Configuration // 설정 정보
public class AppConfig {
    //@Bean memberService -> new MemoryMemberRepository()
    //@Bean orderService -> new  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();
    }
}

- memberService빈을 만드는 코드를 보면 'memberRepository()'를 호출한다.
    -> 이 메서드를 호출하면 'new MemoryMemberRepository()'를 호출한다.
- orderService 빈을 만드는 코드도 동일하게 'memberRepository()'를 호출한다.
    -> 이 메서드를 호출하면  'new MemoryMemberRepository()'를 호출한다.

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

테스트를 해보면

public class ConfigurationSingletonTest {
    @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(memberService.getMemberRepository()).isSameAs(memberRepository);
        assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);

    }
}

 

- memberRepository 인스턴스는 모두 같은 인스턴스가 공유되어 사용된다.
- AppConfig의 자바 코드를 보면 각 1번 'new MemoryMemberRepository()' 호출해서 총 2번 다른 인스턴스가 생성되어야 하는데 두번 호출이 안되는 것일까 ? 실험을 해보자

AppConfig 수정

@Configuration // 설정 정보
public class AppConfig {

    //@Bean memberService -> new MemoryMemberRepository()
    //@Bean orderService -> new  MemoryMemberRepository()


    @Bean //스프링 컨테이너에 빈 등록
    public MemberService memberService(){
        System.out.println("call AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository(){
        System.out.println("call AppConfig.memberRepository");
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService(){
        System.out.println("call AppConfig.orderService");
        return new OrderServiceImpl(memberRepository(),discountPolicy());
    }

    @Bean
    public DiscountPolicy discountPolicy(){
        //return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }
}

    //예상
    //call AppConfig.memberService
    //call AppConfig.memberRepository
    //call AppConfig.memberRepository
    //call AppConfig.orderService
    //call AppConfig.memberRepository


결과

스프링이 싱글톤을 보장해주는 것을 알 수 있음

728x90