Published 2021. 9. 24. 22:27
반응형

✔️ @Configuration과 싱글톤의 관계

스프링 컨테이너에서 관리하도록 해주는 설정 정보 애노테이션 입니다.
@Bean과 같이 사용됩니다.
그렇다면 싱글톤과 무슨 관계가 있을까요?
코드를 보며 설명하겠습니다.

AppConfig

@Configuration
public class AppConfig {

    @Bean
    public Service1 service1() {
        System.out.println("call AppConfig.service1");
        return new ServiceImpl1(discountPolicy());
    }

    @Bean
    public Service2 service2() {
        System.out.println("call AppConfig.service2");
        return new ServiceImpl2(discountPolicy());
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        System.out.println("call AppConfig.discountPolicy");
        return new RateDiscountPolicy();
    }
}

AppConfig에 discountPolicy()라는 빈을 주목해주세요.
순수 자바 코드로만 접근 했을 때 Service1, Service2에 주입할 때 두 번,
discountPolicy()를 빈으로 등록할 때 한 번, 총 는 세 번 호출되어 각각 다른 객체를 가져야 맞습니다.
하지만 결과는 그렇지 않습니다.

    @Test
    void configuration_사용하면_싱글톤임() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        Service1 service1 = context.getBean("service1", Service1.class);
        Service2 service2 = context.getBean("service2", Service2.class);
        DiscountPolicy discountPolicy = context.getBean("discountPolicy", DiscountPolicy.class);
        AppConfig appConfig = context.getBean(AppConfig.class);

        DiscountPolicy discountPolicy1 = service1.getDiscountPolicy();
        DiscountPolicy discountPolicy2 = service2.getDiscountPolicy();

        System.out.println("discountPolicy = " + discountPolicy);
        System.out.println("discountPolicy1 = " + discountPolicy1);
        System.out.println("discountPolicy2 = " + discountPolicy2);
        System.out.println("appConfig = " + appConfig);

        Assertions.assertThat(discountPolicy).isSameAs(discountPolicy1);
        Assertions.assertThat(discountPolicy).isSameAs(discountPolicy2);
        Assertions.assertThat(discountPolicy1).isSameAs(discountPolicy2);
    }


결과를 보면 DiscountPolicy는 모두 같은 주소입니다.
실제로 discountPolicy()는 한 번만 호출되었습니다. 즉, 싱글톤이 유지되었습니다.
이게 어떻게 된 일 일까요?

🔍어떻게 싱글톤이 되었을까?

스프링의 @Configuration은 싱글톤을 유지하게 해주는 애노테이션입니다.
그 원리는 간단하게 알아보면, CGLIB라는 가짜 객체에 있습니다.
appConfig의 클래스 정보를 보면 CGLIB가 있는데 미리 스프링은 미리 가짜 객체에
진짜 객체를 복사해 놓고, 해당 객체가 존재하면 기존에 복사해놨던 객체를 가져오고,
없으면 새로 생성하는 내부 로직을 가지고 있습니다.
이런 원리로 싱글톤을 유지할 수 있게 됩니다.

🔍 @Configuration이 없다면?

없다면 싱글톤이 적용되지 않습니다.
이전과는 다르게 discountPolicy()도 총 세번 호출 되었고,
appConfig의 클래스 정보를 보면 CGLIB도 없습니다.

즉, 특별한 경우가 아니면 @Configration을 사용해야 합니다.

반응형
복사했습니다!