TIL-5 @Autowired @Qualifier @Primary, 어노테이션 생성, 조회한 Bean을 모두 사용하고 싶을 경우
@Autowired는 Type으로 조회한다.
Type으로 조회하기 때문에 다음 코드와 유사하게 동작한다 (실제로는 더 많은 기능을 제공한다.)
ac.getBean(DiscountPolicy.class)
조회 빈을 2개로 만들어 어떤 문제가 발생하는지 알아보자.


DiscountPolicy 인터페이스에 2개의(Fix, Rate) 구현체에 @Component 어노테이션을 달았다.
이제 @Autowired로 DiscountPolicy를 주입 받을려고 하면 아래와 같은 충돌이 일어나게 된다.

기대한 값은 하나의 빈인데 발견한건 2개가 되어 어떤 걸 매칭할지 정할 수 없어 생기는 컴파일 오류이다.
이때 주의할 점은 하위타입으로 지정하는 것인데 이렇게 하면 DIP를 위배하고 유연성이 떨어진다. 그리고 이름은 다르지만 같은 타입의 스프링 빈이 2개 있을 때 해결이 안된다.
스프링 빈을 수동 등록해서 문제를 해결해도 되지만, 이럴 때 해결하는 여러 방법이 있다.
1. @Autowired 필드 명 2. @Quilifier 3. @Primary
@Autowired 필드 명 매칭
@Autowired는 처음에 Type매칭을 시도하고, 이때 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가 매칭한다.

생성자 주입할 때에 파라미터 이름으로 구별하게 시켜주면 해결 가능하다.
@Qualifier사용
@Qualifier추가 구분자를 붙여주는 방법이다. 주입 시 추가적인 방법을 제공하는 것이지 빈 이름을 변경하는 것은 아니다.
'빈 등록시 @Quilifier를 붙여 준다'

기존의 @Component 어노테이션 밑에 각각의 @Qualifier를 붙혀 주었다 그 다음으로
생성자 주입 시 위와 같이 추가를 해주어 해결 할 수 있다.

@Primary 사용
@Primary는 우선순위를 정하는 방법이다. @Autowired시에 여러 번 매칭 되면 @Primary가 우선권을 가진다.
rateDiscountPolicy가 우선권을 가지도록 하자.
Ctrl alt b : 인터페이스에서 구현체로 바로 이동

단순하게 어노테이션만 붙이면 되기에 자주 사용하는 방법이다.
메인DB와 서브DB가 있는 경우

어노테이션 직접 만들기
@Qualifier("mainDiscountPolicy") 이렇게 문자를 적으면 컴파일 시 타입 체크가 안되어 컴파일 오류로 확인할 수가 없다.
다음과 같이 어노테이션을 직접 만들어 문제를 해결할 수 있다.



위와 같이 직접 만든 어노테이션을 사용 할 수 있다.
[Ctrl b : 해당 어노테이션을 사용한 파일들로 이동]

조회한 빈이 모두 필요할 때 List, Map
의도적으로 정말 Fix, Rate 두 스프링 빈이 다 필요한 경우도 있다.
예를들어 할인 서비스를 제공하는데 클라이언트가 종류를 선택할 수 있다고 가정해보면
스프링은 소위 말하는 전략 패턴을 매우 간단하게 구현할 수 있다.
테스트 클래스를 만들어 Map과 List로 DiscountPolicy를 담아보자


Map과 List에 정상적으로 담긴 것을 볼 수 있다.
이를 활용해 할인금액을 리턴하는 메서드를 만들어 보자

전략패턴은 메뉴를 선택할 때 활용할 때 효율적이다.
동적으로 빈을 선택해야할 때 Map으로 받아 활용하면 다형성 코드를 유지하며 사용할 수 있다.