Back-End/Spring

[Spring][스프링 기본편] - 18. @Configuration과 싱글톤

얄루몬 2022. 1. 26. 13:03

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. 출처

https://inf.run/7GX1

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com