전체코드 보기
package hello.core.beanfind;
import hello.core.AppConfig;
import hello.core.dicsount.DiscountPolicy;
import hello.core.dicsount.FixDiscountPolicy;
import hello.core.dicsount.RateDiscountPolicy;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ApplicationContextExtendsFindTest {
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(TestConfig.class);
@Test
@DisplayName("부모 타입을 조회 시, 자식이 둘 이상 있으면, 중복 오류가 발생한다.")
void findBeanByParentTypeDuplicate() {
// DiscountPolicy bean = ac.getBean(DiscountPolicy.class); // NoUniqueBeanDefinitionException
assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(DiscountPolicy.class));
}
@Test
@DisplayName("부모 타입을 조회 시, 자식이 둘 이상 있으면, 빈 이름을 지정하면 된다.") // 그럼 지정해준 빈 이름이 있는지 확인해줌..
void findBeanByParentTypeBeanName() {
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class); // rateDiscountPolicy는 RateDiscountPolicy.class의 인스턴스인가.
}
@Test
@DisplayName("특정 하위 타입으로 조회") // 구체적으로 지정해주는 건 좋은 방법이 아님..
void findBeanBySubType() {
// RateDiscountPolicy로 지정해줬음..
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);// RateDiscountPolicy 클래스에 있는 bean가져오기
assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("부모 타입으로 모두 조회하기")
void findAllBeanByParentType() {
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
assertThat(beansOfType.size()).isEqualTo(2);
for (String key : beansOfType.keySet()) { // 실제 테스트코드에서는 print를 남겨두지 않는게 좋음 -> 자동통과 시스템을 만드는데 눈으로 보고 있을 수는 없음..
System.out.println("key = " + key + ", value = " + beansOfType.get(key));
}
}
@Test
@DisplayName("부모 타입으로 모두 조회하기 - Object") // 자바 객체는 모든 게 Object타입이기 때문에
void findAllBeanByObjectType() {
Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
for (String key : beansOfType.keySet()) { // 스프링 빈에 등록된 모든 객체가 나옴..
System.out.println("key = " + key + ", value = " + beansOfType.get(key));
}
}
@Configuration
static class TestConfig {
@Bean
public DiscountPolicy rateDiscountPolicy() {
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy() {
return new FixDiscountPolicy();
}
}
}
스프링 빈 조회 - 상속관계
- 부모 타입으로 조회하면, 자식 타입도 함께 조회한다.
- 자바에서 객체의 최고 부모인 Object타입으로 조회하면, 모든 스프링 빈을 조회할 수 있다.
1번 조회 시 : 1, 2, 3, 4, 5, 6, 7번 조회
2번 조회 시 : 4, 5번 조회
3번 조회 시 : 6, 7번 조회
4번 조회 시 : 4번 조회
5번 조회 시 : 5번 조회
6번 조회 시 : 6번 조회
7번 조회 시 : 7번 조회
(ERROR) 부모 타입을 조회 시, 자식이 둘 이상 있으면, 중복 오류 발생
📌 DiscountPolicy bean = ac.getBean(DiscountPolicy.class);
DiscountPolicy.class의 빈을 가져와라 → 빈이 2개 이상이기 때문에 중복오류 발생(NoUniqueBeanDefinitionException)
📌 assertThrows(NoUniqueBeanDefinitionException.class, () → ac.getBean(DiscountPolicy.class));
() → ac.getBean(DiscountPolicy.class)이걸 실행했을, 때 NoUniqueBeanDefinitionException에러가 뜬다면, 테스트 성공
@Test
@DisplayName("부모 타입을 조회 시, 자식이 둘 이상 있으면, 중복 오류가 발생한다.")
void findBeanByParentTypeDuplicate() {
// DiscountPolicy bean = ac.getBean(DiscountPolicy.class); // NoUniqueBeanDefinitionException
assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(DiscountPolicy.class));
}
해결방법1 - 빈 이름 지정
부모 타입을 조회 시, 자식이 둘 이상있으면, 빈 이름을 지정하면 된다.
📌 DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
DiscountPolicy 클래스에서 메소드명이 rateDiscountPolic인 beand을 가져와라
📌 assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
rateDiscountPolicy는 RateDiscountPolicy.class의 인스턴스인가
@Test
@DisplayName("부모 타입을 조회 시, 자식이 둘 이상 있으면, 빈 이름을 지정하면 된다.")
void findBeanByParentTypeBeanName() {
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}
해결방법2 - 특정 하위 타입으로 조회(추천ㄴㄴ)
DiscountPolicy보다 더 작은 특정 하위 타입인 RateDiscountPolicy으로 조회한다.
구체적으로 지정해주는 건 좋은 방법이 아니기 때문에 사용하지 않는게 좋다.
📌 RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class)
RateDiscountPolicy 클래스에 있는 bean가져오기
📌 assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
bean은 RateDiscountPolicy.class의 인스턴스인가
@Test
@DisplayName("특정 하위 타입으로 조회")
void findBeanBySubType() {
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
}
해결방법3 - 부모 타입으로 모두 조회하기
부모타입인 DiscountPolicy로 조회하는 방법
위에서 오류가 났던 이유는 DiscountPolicy.class의 빈을 보려고 했기 때문이다.
bean의 Type으로 조회하면 볼 수 있다.
📌 Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
DiscountPolicy.class를 타입으로 가지고 있는 것을 가져와라.
getBeanOfType는 Map<key메소드명, value주소 값> 으로 값을 준다.
📌 assertThat(beansOfType.size()).isEqualTo(2);
DiscountPolicy을 타입으로 가지고 있는 것의 길이는 2개인가
📌 for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + ", value = " + beansOfType.get(key));}
실제 테스트코드에서는 print를 남겨두지 않는게 좋음 → 자동통과 시스템을 만드는데 눈으로 보고 있을 수는 없기 때문..
@Test
@DisplayName("부모 타입으로 모두 조회하기")
void findAllBeanByParentType() {
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
assertThat(beansOfType.size()).isEqualTo(2);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + ", value = " + beansOfType.get(key));
}
}
프린트 값
해결방법4 - 부모 타입(Obgect)으로 모두 조회하기
자바에서 Object는 모든 객체의 부모이기 때문에 스프링 빈에 등록된 모든 객체가 나온다.
📌 Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
Object.class 타입을 모두 가져와라
📌 for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + ", value = " + beansOfType.get(key));}
스프링 빈에 등록된 모든 객체가 나온다.
@Test
@DisplayName("부모 타입으로 모두 조회하기 - Object")
void findAllBeanByObjectType() {
Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + ", value = " + beansOfType.get(key));
}
}
'공부 > Spring' 카테고리의 다른 글
[Spring] 다양한 설정 형식 지원 - 자바 코드, XMl (0) | 2023.11.09 |
---|---|
[Spring] Beanfactory와 ApplicationContext (0) | 2023.11.07 |
[Spring] 스프링 빈 조회 - 동일한 타입이 둘 이상일 때 (0) | 2023.11.07 |
[Spring] 스프링 빈 조회 - 기본 (0) | 2023.11.06 |
[Spring] 스프링으로 전환하기 (0) | 2023.11.01 |