스프링 핵심원리 기본편 - 의존관계 자동 주입(5)|조회한 빈이 모두 필요할 때, List, Map

2024. 5. 7. 03:36· 인프런 김영한 강의 정리/스프링 핵심원리 기본편
목차
  1. 1. 예제: Map으로 2개의 빈 받아오기
  2. 2. OCP와 전략패턴
728x90

동적으로 빈을 선택해야할 때, Map으로 빈을 받으면 편리하다.
예제에서는 두가지 할인 정책이 있는데, Map에 key값만 넘겨주면 각 할인 정책에 맞는 할인가를 알 수 있다.
 

1. 예제: Map으로 2개의 빈 받아오기

DiscountPolicy 인터페이스가 있다.
fixDiscountPolicy와 rateDiscountPolicy는 구현 클래스다.
 
✅FixDiscountPolicy 

@Component
public class FixDiscountPolicy implements DiscountPolicy {

    private int discountFixAmount = 1000; //1000원 할인
    @Override
    public int discount(Member member, int price) {
        if(member.getGrade() == Grade.VIP){
            return discountFixAmount;
        } else {
            return 0;
        }
    }
}

@Component를 붙여줘서 빈에 등록시킨다.
항상 1000원을 할인하는 코드다.
 
✅RateDiscountPolicy 

@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy{

    private int discountPercent = 10;

    @Override
    public int discount(Member member, int price) {
        if (member.getGrade() == Grade.VIP){
            return price * discountPercent / 100;
        } else {
            return 0;
        }
    }
}

 
직접 만든 어노테이션인 @MainDiscountPolicy를 붙여서 의존관계 생성자 자동주입시 RateDiscountPolicy를 선택하도록 한다. (빈 충돌 방지)
 
🤔의문점
- Map 또는 List에 두가지 정책을 담을 때 어떻게 @MainDiscountPolicy가 붙은 RateDiscountPolicy만 들어오는게 아니라 FixDiscountPolicy까지 들어오지?
💡의문 해결
- @MainDiscountPolicy을 생성자에 사용함으로써 생성자로 초기화하여 값을 넣을 때, 우선적으로 의존성 주입을 받는 것이다. @Qualifier을 써도 @Component가 붙은 DiscountPolicy의 하위클래스들이 Bean으로 등록된다.
 
*참고
@MainDiscountPolicy는 @Qualifier기능을 담고 있으며 컴파일시 타입을 확인할 수 있게하는 어노테이션이다.
 
✅ 2개의 빈을 Map 또는 List에 넣은 테스트 

public class AllBeanTest {
    // 테스트 클래스 선언
    @Test
    // 테스트 메서드 선언
    void findAllBean(){
        // Spring 컨텍스트를 AutoAppConfig.class, DiscountService.class를 이용해 생성
        // AutoAppConfig.class 안넣으면 DiscountService에 있는 Map, List객체 빈값들어옴.
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
        
        // 컨텍스트에서 DiscountService 타입의 빈을 가져옴
        DiscountService discountService = ac.getBean(DiscountService.class);
        
        // Member 인스턴스 생성
        Member member = new Member(1L, "userA", Grade.VIP);
        
        // DiscountService를 이용해 fixDiscountPolicy정책 할인 가격 계산
        int discountPrice = discountService.discount(member,10000,"fixDiscountPolicy");
        // 계산된 할인 가격이 1000원인지 확인
        Assertions.assertThat(discountPrice).isEqualTo(1000);

        // 다른 할인 정책을 사용하여 rateDiscountPolicy정책 할인 가격 계산
        int rateDiscountPrice = discountService.discount(member, 20000, "rateDiscountPolicy");
        // 계산된 할인 가격이 2000원인지 확인
        Assertions.assertThat(rateDiscountPrice).isEqualTo(2000);

    }

    // 테스트용 내부 정적 클래스 따로 만들음.
    @Component
    static class DiscountService{
        // 할인 정책을 저장하는 Map
        private final Map<String, DiscountPolicy> policyMap;
        
        // 할인 정책 객체 리스트
        private final List<DiscountPolicy> policies;
        
        // 생성자에 @Autowired를 사용하여 의존성 주입
        @Autowired
        public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
            this.policyMap = policyMap;
            this.policies = policies;
            // policyMap과 policies 내용을 콘솔에 출력
            System.out.println("policyMap = " + policyMap);
            System.out.println("policies = " + policies);
        }

        // 할인 코드에 따라 할인 가격 계산 메서드
        public int discount(Member member, int price, String discountCode) {
            // 할인 정책을 Map에서 가져옴
            DiscountPolicy discountPolicy = policyMap.get(discountCode);
            // 할인 정책에 따라 할인 가격 계산 후 반환
            return discountPolicy.discount(member, price);
        }
    }
}

 
1. Map의 value 타입과 List 의 타입이 DiscountPolicy다. 
2. DiscountPolicy 타입으로 된 Bean을 탐색한다. 
3. AutoAppConfig에서 ComponentScan을 통해서 이미 스프링 빈으로 등록해둔 FixDiscountpolicy, RateDiscountPolicy를 get메서드를 이용해서 가져온다.

-> Test코드에서 getBean으로 내부 정적클래스인 DiscountService 빈을 가져온다. 

4. 어떤 정책을 사용할 지 String으로 지정해서 사용할 수 있다.

5. 이렇게 Map 또는 List로 하위타입 빈을 담으면 다형성을 적극 활용할 수 있는 코드가 된다. 
 
✅Map과 List에 담기는 값 확인

policyMap = {fixDiscountPolicy=hello.core.discount.FixDiscountPolicy@30e92cb9, rateDiscountPolicy=hello.core.discount.RateDiscountPolicy@7fae4d4a}
policies = [hello.core.discount.FixDiscountPolicy@30e92cb9, hello.core.discount.RateDiscountPolicy@7fae4d4a]

 
policyMap
Key - String타입의 할인정책 클래스
Value - DiscountPolicy타입의 빈 인스턴스
 
아래와 같이 Key값으로 value를 조회한다.

// 할인 정책을 Map에서 가져옴
DiscountPolicy discountPolicy = policyMap.get(discountCode);

 
FixDiscountPolicy 또는 RateDiscountPolicy의 discount메서드를 호출할 수 있다. 

discountPolicy.discount(member, price);

 
 

2. OCP와 전략패턴

이러한 방식은 객체지향 설계 원칙 중 개방-폐쇄 원칙 (Open-Closed Principle, OCP) 을 따른다.
Map에서 알고리즘을 꺼내 사용하는 방식으로 전략패턴을 구현할 수 있다.
 
1️⃣확장에 열려 있음
- 새로운 전략(알고리즘)이 필요할 경우, 새로운 전략 클래스를 만들고 스프링 빈으로 등록하기만 하면 된다. 이 클래스를 Map에 추가하기만 하면, 시스템의 나머지 부분을 변경할 필요 없이 새로운 기능을 사용할 수 있다.
 
2️⃣수정에 닫혀 있음
- 기존의 코드(예를 들어 DiscountService와 같은 서비스)는 전략이 추가되거나 변경될 때 수정할 필요가 없다.
Map에서 필요한 전략을 선택하기만 하면 되기 때문에, 기존 코드는 변경하지 않아도 된다.
 
3. 의존성 수동 주입과 자동 주입은 언제 써야하는가
✔️비즈니스 로직은 웬만하면 자동 주입을 하는게 좋다.
- 실무에서는 관리하는 빈이 많아질수록 유지보수하기가 어려워지기 때문이다.

✔️기술지원 로직
- 주요 비즈니스 로직이 아닌 비즈니스 로직이 돌아가게끔 하기위한 데이터베이스 연결같은 기술지원로직은 수동주입을 하는게 좋다.

✔️비즈니스 로직이어도 다형성을 적극 활용하는 경우
- 빈을 직관적으로 파악하기 위해 수동 주입을 하는게 좋다.

728x90

'인프런 김영한 강의 정리 > 스프링 핵심원리 기본편' 카테고리의 다른 글

스프링 컨텍스트 이해와 선택: 애플리케이션 요구에 맞는 올바른 컨텍스트 사용하기  (0) 2024.05.07
스프링 핵심 원리 기본편 - 빈 생명주기 콜백  (0) 2024.05.07
스프링 핵심 원리 기본편 - 의존관계 자동 주입(4)|조회하는 빈이 2개 이상,해결법, 애노테이션 직접 만들기  (0) 2024.05.06
스프링 핵심원리 기본편 - 의존관계 자동 주입(3)|롬복과 최신 트랜드  (0) 2024.05.06
스프링 핵심 원리 기본편 - 의존관계 자동 주입(2)|옵션처리  (0) 2024.05.04
  1. 1. 예제: Map으로 2개의 빈 받아오기
  2. 2. OCP와 전략패턴
'인프런 김영한 강의 정리/스프링 핵심원리 기본편' 카테고리의 다른 글
  • 스프링 컨텍스트 이해와 선택: 애플리케이션 요구에 맞는 올바른 컨텍스트 사용하기
  • 스프링 핵심 원리 기본편 - 빈 생명주기 콜백
  • 스프링 핵심 원리 기본편 - 의존관계 자동 주입(4)|조회하는 빈이 2개 이상,해결법, 애노테이션 직접 만들기
  • 스프링 핵심원리 기본편 - 의존관계 자동 주입(3)|롬복과 최신 트랜드
백엔드 개발자 - 젤리곰
백엔드 개발자 - 젤리곰
오늘도 배움이 있는 하루가 되길 바라는 개발자
백엔드 개발자 - 젤리곰
backend-gummyBear
백엔드 개발자 - 젤리곰
전체
오늘
어제
  • 분류 전체보기 (144) N
    • 인프런 김영한 강의 정리 (60)
      • 스프링 핵심원리 기본편 (12)
      • 모든 개발자를 위한 HTTP 웹 기본 지식 (10)
      • 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 (3)
      • 자바 ORM 표준 JPA 프로그래밍 기본편 (28)
      • 실전! Querydsl (6)
    • Spring (2)
    • 프로젝트일지 (6)
    • 프로그래밍 언어 (20)
      • Java (17)
      • JavaScript (3)
      • Python (0)
    • 데이터베이스 (4) N
      • Oracle (2)
      • ORM (1)
      • SQL 튜닝 (1) N
    • 형상관리 (1)
      • Git (0)
    • 알고리즘&자료구조 (34)
      • Algorithm (31)
      • Data Structure (1)
    • CS지식 (4)
    • Cloud (5)
    • 일기 (7)
      • 공부 일기 (3)
      • 독서 일기 (2)
      • 마음 일기 (2)

블로그 메뉴

  • 홈
  • 태그

공지사항

인기 글

태그

  • 객체지향의사실과오해
  • LeetCode200번
  • 다운캐스팅
  • LeetCode17번
  • 업캐스팅
  • dfs알고리즘
  • 힙자료구조
  • 커스텀annotation
  • 데이터베이스정규화
  • 스프링컨텍스트
  • ORM프레임워크
  • jquery와javascript
  • 인프콘
  • SublimeText단축키
  • 클라이언트서버통신
  • 프론트엔드개발자업무
  • 인터페이스
  • 프론트엔드역사
  • #{}와${}의차이
  • 객체지향방법론

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
백엔드 개발자 - 젤리곰
스프링 핵심원리 기본편 - 의존관계 자동 주입(5)|조회한 빈이 모두 필요할 때, List, Map
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.