INFLEARN

[스프링 핵심 원리 - 기본편] 15. 조회한 빈이 모두 필요할 때: List, Map 활용

ch010104 2026. 3. 21. 00:01
  • 항상 하나의 빈만 사용하는 것이 아니라, 클라이언트의 선택에 따라 여러 할인 정책(fix, rate)을 유연하게 적용해야 할 때가 있음
  • 스프링은 전략 패턴(Strategy Pattern)을 구현할 수 있도록 특정 타입의 모든 빈을 List나 Map으로 주입받는 기능을 제공

1. 전체 빈 조회 테스트 코드

DiscountService는 모든 DiscountPolicy를 주입받아, 상황에 맞는 정책을 골라서 실행

package com.example.spring_study.autowired;

import com.example.spring_study.AutoAppConfig;
import com.example.spring_study.discount.DiscountPolicy;
import com.example.spring_study.member.Grade;
import com.example.spring_study.member.Member;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;
import java.util.Map;

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

public class AllBeanTest {

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

        DiscountService discountSerivce = ac.getBean(DiscountService.class);
        Member member = new Member(1L, "userA", Grade.VIP);
        int discountPrice = discountSerivce.discount(member, 10000, "fixDiscountPolicy");

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

        int rateDiscountPrice = discountSerivce.discount(member, 20000, "rateDiscountPolicy");
        assertThat(rateDiscountPrice).isEqualTo(2000);

    }

    static class DiscountService{

        // Map으로 모든 DiscountPolicy를 받음
        private final Map<String, DiscountPolicy> policyMap;
        private final List<DiscountPolicy> policies;

        public 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);
        }
    }
}


2. 로직 및 주입 분석

주입 방식

  • Map<String, DiscountPolicy>: 키(key)에 스프링 빈의 이름이 들어가고, 값(value)에 해당 타입의 스프링 빈 객체가 담김
  • List<DiscountPolicy>: 해당 타입으로 조회된 모든 스프링 빈을 리스트에 담아줌
  • 만약 일치하는 타입의 빈이 하나도 없다면, 스프링은 에러를 내지 않고 빈 컬렉션이나 빈 Map을 주입

로직 분석

  • discount() 메서드는 discountCode로 "fixDiscountPolicy"가 넘어오면 Map에서 해당 빈을 찾아 고정 할인 로직을 실행
  • "rateDiscountPolicy"가 넘어오면 정률 할인 빈을 찾아 실행합니다. 이를 통해 다형성을 극대화한 전략 패턴을 구현할 수 있음

3. 참고: 컨테이너 생성과 동시에 빈 등록하기

new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class); 코드는 다음 두 가지를 동시에 수행

  1. AutoAppConfig.class: 설정 정보를 읽어 빈을 스캔하고 등록
  2. DiscountService.class: 해당 클래스를 스프링 컨테이너에 직접 스프링 빈으로 등록

요약

  • 특정 타입의 빈이 모두 필요할 때는 List나 Map을 사용하면 매우 편리
  • 스프링은 주입 시점에 해당 타입의 모든 빈을 자동으로 찾아 컬렉션에 채워줌.
  • 이 방식은 동적인 선택권이 필요한 비즈니스 로직(다양한 결제 수단, 다양한 할인 정책 등)에서 강력한 힘을 발휘