강의

멘토링

로드맵

Inflearn brand logo image

인프런 커뮤니티 질문&답변

jwooo님의 프로필 이미지
jwooo

작성한 질문수

스프링 핵심 원리 - 기본편

@Configuration에 대한 질문입니다.

작성

·

330

1

복습을 하다가 @Configuration에 대해서 복습을 하다 이상한 점이 발견되어 질문 드립니다.

@Configuration을 클래스 위에 붙이면 해당 클래스를 스프링 컨테이너에서 싱글톤으로 관리한다고 들었습니다. 그런데 StatefulServiceTest 코드의 TestConfig에서 @Configuration을 제거한 상태로 테스트를 돌려보니 같은 객체가 리턴되는 것을 보고 AppConfig에서도 @Configuration을 제거하고 ConfigurationSingletonTest 테스트를 실행해보았더니 다른 객체가 리턴되어서 어떤 이유인지 궁금해 질문 올립니다. 아래는 해당 코드들 입니다.

 

StatefualServiceTest

package hello.core.singleton;

import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;

class StatefulServiceTest {

    @Test
    void StatefulServiceSingleton() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);

        // A 사용자 10000원 주문
        statefulService1.order("userA", 10000);
        // B 사용자 20000원 주문
        statefulService2.order("userB", 20000);

        System.out.println("statefulService1 = " + statefulService1);
        System.out.println("statefulService2 = " + statefulService2);

        MemberServiceImpl bean1 = ac.getBean(MemberServiceImpl.class);
        MemberServiceImpl bean2 = ac.getBean(MemberServiceImpl.class);

        System.out.println("bean1 = " + bean1.getMemberRepository());
        System.out.println("bean2 = " + bean2.getMemberRepository());

        // A사용자 주문 금액 조회
        int price = statefulService1.getPrice();
        System.out.println("price = " + price);

        assertThat(statefulService1.getPrice()).isEqualTo(20000);

    }


    static class TestConfig {
        @Bean
        public StatefulService statefulService() {
            return new StatefulService();
        }

        @Bean
        public MemberService memberService() {
            return new MemberServiceImpl(memberRepository());
        }

        @Bean MemberRepository memberRepository() {
            return new MemoryMemberRepository();
        }
    }

}

테스트 실행 시 로그

 

 

ConfigurationSingletonTest

package hello.core.singleton;

import hello.core.AppConfig;
import hello.core.member.MemberRepository;
import hello.core.member.MemberServiceImpl;
import hello.core.order.OrderServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

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

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

    }

    @Test
    void configurationdeep() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
        AppConfig bean = ac.getBean(AppConfig.class);
        System.out.println("bean = " + bean.getClass());
    }
}

테스트 실행 시 로그

 

AppConfig

package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
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() {
        System.out.println("call AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemoryMemberRepository 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 RateDiscountPolicy();
    }
}

답변 1

3

안녕하세요. 박정우님, 공식 서포터즈 David입니다.

TestConfig 내에서는 memberRepository()가 MemberService를 생성할 때 한 번 호출됩니다. 즉, MemberService가 생성될 때 주입된 memberRepository 객체는 MemberService 빈 내에 할당된 상태이며 변경되지 않습니다. 따라서, MemberService를 컨테이너로부터 찾아와서 getMemberRepository()를 호출하면 동일한 객체만을 반환할 수 밖에 없습니다.

다르게 나오는 걸 보고 싶으시다면 TestConfig 내에서 memberRepository()를 여러 번 호출하는 코드를 작성해보시길 권장합니다.

또한 ac.getBean(MemberRepository.class)를 하셔서 반환되는 객체와도 비교해보시면 좋을 것 같습니다.

감사합니다.

jwooo님의 프로필 이미지
jwooo
질문자

해결된 것 같습니다. 좋은 정보 주셔서 감사드립니다..!

jwooo님의 프로필 이미지
jwooo

작성한 질문수

질문하기