jhhan의 블로그

스프링 코어(13) - 조회 빈이 모두 필요한 경우 본문

Spring

스프링 코어(13) - 조회 빈이 모두 필요한 경우

jhhan000 2021. 8. 15. 13:01

이번 포스트는 조회한 빈이 여러개이고, 여러 개인 빈이 모두 필요한 경우에 대해서 살펴보겠습니다.

 

 

앞에서는 조회한 빈이 여러개인 경우 그 중에 1개만 선택해서 진행하는 것으로 했습니다.

하지만 어떤 경우에는 조회한 빈이 모두 필요할 때도 있습니다.

전에 사용했던 것을 예시로 들면 DiscountPolicy를 사용했었죠.

DiscountPolicy는 fix와 rate으로 나뉘어져 있는데, 이 2개 모두 필요하다고 생각해보면 되겠습니다.
(할인을 여러가지 경우로 나누어서 생각하는 것이죠!)

 

 

테스트 파일을 만들어서 진행할 것입니다.

hello.core.autowired.AllBeanTest 경로가 되도록 진행하겠습니다.

public class AllBeanTest {

    @Test
    void findAllBean() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(DiscountService.class);
        System.out.println(ac);
    }

    /**
     * 2021.08.13
     * 기존의 OrderServiceImpl을 쓰기에는 너무 지저분해질 것 같아서 새로 클래스 추가
     */
    static class DiscountService {
        private final Map<String, DiscountPolicy> policyMap;
        private final List<DiscountPolicy> policies;

        DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
            this.policyMap = policyMap;
            this.policies = policies;
            System.out.println("policyMap = " + policyMap);
            System.out.println("policies = " + policies);
        }
    }
}

코드는 이렇게 됩니다.

참고로

DiscountService를 따로 만들기는 코드가 복잡해질 수 도 있기 때문에 

이렇게 테스트에서만 사용할 static class를 만들어서 진행합니다.

 

조회한 모든 빈을 불러오기 위해서 Map과 List를 사용합니다.

이 테스트를 실행해본다면

잘 출력되는 것을 확인할 수 있습니다.

근데 빈이 아무것도 없습니다.

왜냐하면 DiscountService만을 빈으로 등록했기 때문입니다.

그러면 DiscountPolicy들도 빈으로 등록해서 진행해봐야겠죠.

코드를 변경합니다.

public class AllBeanTest {

    @Test
    void findAllBean() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
        System.out.println("ac = " + ac);
    }

    /**
     * 2021.08.13
     * 기존의 OrderServiceImpl을 쓰기에는 너무 지저분해질 것 같아서 새로 클래스 추가
     */
    static class DiscountService {
        private final Map<String, DiscountPolicy> policyMap;
        private final List<DiscountPolicy> policies;

        DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
            this.policyMap = policyMap;
            this.policies = policies;
            System.out.println("policyMap = " + policyMap);
            System.out.println("policies = " + policies);
        }
    }
}

이전에 만들었던 AutoAppConfig 클래스를 통해 등록 빈을 가져옵니다.

그리고 테스트를 돌려보면

이렇게 나온 것을 확인할 수 있습니다.

이번에는 빈 등록이 잘 되서 Map과 List에 나오는 것을 확인할 수 있습니다!
(사실 Map위주로 사용할 것입니다. List는 이런 식으로 사용할 수도 있다는 것을 보여주기 위해서 넣었습니다.)

Map의 경우 key에 스프링 빈의 이름을 넣고, value에 DiscountPolicy로 조회한 모든 스프링 빈을 넣어줍니다.

List의 경우 Map의 value 값만 들어간다고 생각하면 됩니다.

 

 

그럼 이렇게 나오는 결과를 토대로 무언가를 진행해 봐야겠죠..?

예제를 하나 만들어보겠습니다.

import static org.assertj.core.api.Assertions.assertThat;

public class AllBeanTest {

    @Test
    void findAllBean() {
//        ApplicationContext ac = new AnnotationConfigApplicationContext(DiscountService.class);
        ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);

        DiscountService discountService = ac.getBean(DiscountService.class);
        Member member = new Member(1L, "UserA", Grade.VIP);
        int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy");
        System.out.println("discountPrice = " + discountPrice);

        assertThat(discountService).isInstanceOf(DiscountService.class);
        assertThat(discountPrice).isEqualTo(1000);

        int rateDiscountPrice = discountService.discount(member, 20000, "rateDiscountPolicy");
        System.out.println("rateDiscountPrice = " + rateDiscountPrice);

        assertThat(rateDiscountPrice).isEqualTo(2000);
    }

    /**
     * 2021.08.13
     * 기존의 OrderServiceImpl을 쓰기에는 너무 지저분해질 것 같아서 새로 클래스 추가
     */
    static class DiscountService {
        private final Map<String, DiscountPolicy> policyMap;
        private final List<DiscountPolicy> policies;

        DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
            this.policyMap = policyMap;
            this.policies = policies;
            System.out.println("policyMap = " + policyMap);
            System.out.println("policies = " + policies);
        }

        public int discount(Member member, int price, String discountCode) {
            DiscountPolicy discountPolicy = policyMap.get(discountCode);
            return discountPolicy.discount(member, price);
        }
    }
}

이런 식으로 DiscountPolicy를 다르게 적용해봤습니다.

그럼 어떻게 나올까요?

이렇게 결과가 나오는 것을 볼 수 있습니다.

 

어떻게 진행되는지 한번 간략히 알아보겠습니다.

  1. DiscountService는 Map으로 모든 DiscountPolicy를 주입받음.
  2. discount() 메서드가 실행되면
  3. 넘어온 DiscountCode로 해당 스프링 빈을 찾음.
  4. 스프링 빈에 해당하는 할인을 적용해서 리턴
      fix - 1000원 할인   /   rate - 10% 할인

이렇게 진행이 됩니다.

 

 

 

이렇게 해서 조회한 빈을 모두 사용할 수 있는 방법에 대해 알아봤습니다.

필수는 아니지만, 한번은 써먹을 수 있다는 생각이 듭니다.

 

 

 

 

이렇게 해서 이번 포스트를 마칩니다.

 

 

 

출처: 인프런 - 스프링 핵심원리(기본편) by 김영한