기본 개념을 포스팅하는 건 별로 의미가 없다는 생각이 들어 놓은 지 좀 되었는데.
이번에는 내가 이해한 게 맞는지 혼란이 와서 나중에 다시 읽어보기 위해 작성하게 되었다.
만약 DiscountPolicy라는 인터페이스를 구현한 FixDiscoutPolicy와 VariableDiscountPolicy라는 클래스가 있을 때.
클라이언트가 고정 할인과 비율 할인을 자유롭게 선택할 수 있도록 하려면 어떻게 해야할까?
각 코드를 따로 작성하는 방법도 있겠지만 다형성을 활용하여 하나의 로직으로 모두 해결할 수 있다.
public class AllBeanTest {
@Test
void findAllBean() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
DiscountService discountService = ac.getBean(DiscountService.class);
Member member = new Member(1L, Grade.VIP, "userA");
int discountPrice = discountService.discount(member,10000,"fixDiscountPolicy");
Assertions.assertThat(discountService).isInstanceOf(DiscountService.class);
Assertions.assertThat(discountPrice).isEqualTo(1000);
int variableDiscount = discountService.discount(member, 20000, "variableDiscountPolicy");
Assertions.assertThat(variableDiscount).isEqualTo(2000);
}
static class DiscountService {
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);
}
}
}
내가 헷갈렸던 부분들에 대한 정리.
1. @Component도 없고 @Autowired도 없고 대체 어디서 빈을 주입 받고 있는 거지?
=> AnnotiationConfigApplicationContext를 생성할 때 인자로 받은 클래스들을 자동으로 스프링 빈 컨테이너에 등록해준다.
그리고 innerClass인 DiscountService에서 해당 클래스를 검색하면 자동으로 해당 타입(Map, List)에 맞는 컬렉션 자료들을 찾아서 반환하는 것이다.
2. Map<String, DiscountPolicy>에서 String에 들어가는 게 뭐지?
=> 불러온 맵을 표준 출력으로 확인해보면 이런 결과가 나온다.
fixDiscountPolicy=helloProject.core.discount.FixDiscountPolicy@6da00fb9,
variableDiscountPolicy=helloProject.core.discount.VariableDiscountPolicy@a202ccb
스프링 컨테이너에 빈은 이름과 객체로 저장되는데, Map으로 스프링 빈에 저장된 클래스를 탐색하면 해당 이름과 객체를 Map 형태로 주입해준다. 그 키와 값을 그대로 받은 것이다.
그리고 빈의 이름은 "클래스명의 제일 앞 글자를 소문자로 변경한 형태"로 저장되기 때문에 해당 규칙에 따라 원하는 빈을 호출해주면 된다.
로직 정리.
1.
static class DiscountService {
private final Map<String, DiscountPolicy> policyMap;
// Map<String, DiscountPolicy>과 같은 타입의 스프링 빈을 찾아 주입
private final List<DiscountPolicy> policies; // 의미 없는 코드 무시할 것
@Autowired //생성자가 하나면 생략 가능하지만 일단 적었다.
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);
//discountCode 파라미터에 빈의 이름만 적어주면 해당 빈 객체를 주입하여 선택권을 준다.
//discountPolicy.discount(member, price)는 기존에 존재하던 메서드이다.
return discountPolicy.discount(member, price);
}
2.
void findAllBean() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
// AnnotationConfigApplicatonContext는 말 그대로 "스프링 컨테이너" (여기까지는 순수한 자바 코드)
// 스프링이 이 코드를 참고하여 AutoConfig.class, DiscountService.class를 스프링 빈으로 등록한다.
DiscountService discountService = ac.getBean(DiscountService.class);
Member member = new Member(1L, Grade.VIP, "userA");
int discountPrice = discountService.discount(member,10000,"fixDiscountPolicy");
// 빈 이름을 인자로 넣고 테스트 성공
Assertions.assertThat(discountService).isInstanceOf(DiscountService.class);
Assertions.assertThat(discountPrice).isEqualTo(1000);
int variableDiscount = discountService.discount(member, 20000, "variableDiscountPolicy");
Assertions.assertThat(variableDiscount).isEqualTo(2000);
}
역시 헷갈릴 때는 한 번 기록하는 게 제일 좋은 방법인 것 같다.
정리하느라 진도를 못 나가기는 했지만.. 이해하지 못하고 넘어가는 것보다는 낫겠지 🥲
'Language & Framework > Spring' 카테고리의 다른 글
스프링 시큐리티의 DelegatingFilterProxy, FilterChainProxy, SecurityFilterChain에 대해 알아보자. (0) | 2022.09.20 |
---|---|
꾸준히 듣게되는 Servlet과 Dispatcher Servlet에 대해 알아보자 (0) | 2022.08.10 |
MVC패턴이란? Spring MVC의 기본 흐름을 알아보자. (0) | 2022.07.29 |
자바 스프링부트 에러(2) java.lang.IllegalStateException: Ambiguous mapping (0) | 2022.07.09 |
자바 스프링부트 에러(1)java.lang.IllegalAccessError 나처럼 고통 받을 누군가를 위하여.. (0) | 2022.06.30 |