AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 빈 출력하기")
void findAllBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("Bean = " + beanDefinitionName + "Object" + bean);
}
}
@Test
@DisplayName("어플리케이션 빈 출력하기")
void findApplicationBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){
Object bean = ac.getBean(beanDefinitionName);
System.out.println("Bean = " + beanDefinitionName + "Object" + bean);
}
}
}
ac.getBean(빈이름, 타입)
ac.getBean(타입)
조회 대상 스프링 빈이없으면 예외발생
NoSuchBeanDefinitionException: No bean named 'xxxxx' available;
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 이름으로 조회")
void findBeanByName(){
MemberService memberService = ac.getBean("memberService",MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈 이름없이 타입으로 조회")
void findBeanByType(){
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
타입으로 쓰면 좋으나 타입이 여러개일때 곤란해 질수있기 때문에 이름을 작성해주는것이 좋다
인터페이스로 조회하면 인터페이스의 구현체가 대상이 된다.
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입 조회시 같은 타입이 두개있으면 오류가 발생한다.")
void findBeanByTypeDuplicate(){
// MemberRepository bean = ac.getBean(MemberRepository.class);
//MemberRepository bean = ac.getBean("memberRepository1",MemberRepository.class); Assertions.assertThrows(NoUniqueBeanDefinitionException.class,
()-> ac.getBean(MemberRepository.class));
}
@Test
@DisplayName("특정 타입을 모두 조회하기")
void findAllBeanBYType() {
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
for(String key : beansOfType.keySet()){
System.out.println("key = "+ key + " value =" + beansOfType.get(key));
}
System.out.println("beanofType" + beansOfType);
assertThat(beansOfType.size()).isEqualTo(2);
}
@Configuration
static class SameBeanConfig {
@Bean
public MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
타입만 쓰는게 아니라 메소드 이름도 적어주면 된다.
부모타입을 조회하면, 자식타입도 함께 조회한다.
1번에 2,3의 자식있고 2에 4,5가 3에 6,7이 있을때
1번을 조회하면 1,2,3,4,5,6,7이 다조회되고
2를 조회하면 2,4,5가 3을 조회하면 3,6,7이 조회된다.
@Test
@DisplayName("부모타입으로 모두 조회하기")
void findAllBeanByParentType(){
Map<String, DiscountPolicy> beanOfType = ac.getBeansOfType(DiscountPolicy.class);
assertThat(beanOfType.size()).isEqualTo(2);
for(String key : beanOfType.keySet()){
System.out.println("key = " + key + "value" +beanOfType.get(key));
}
}
@Test
@DisplayName("부모타입으로 모두 조회하기 - Object")
void findAllBeanByObjectType(){
Map<String, Object> beanOfType = ac.getBeansOfType(Object.class);
for(String key : beanOfType.keySet()){
System.out.println("key = " + key + "Object" +beanOfType.get(key));
}
}
Object로 조회하면 모든 빈이 나온다. 이유는 Object는 모든타입의 부모이기 때문이다.
@Autowired 필드명매칭, @Quilifier, @Primary
이렇게 3가지 방법으로 오류가 터지지 않게 해결할수있다.
@Autowired
private DiscountPolicy discountPolicy
위 인터페이스를 사용한것을
@Autowired
private DiscountPolicy rateDiscountPolicy
아래의 상속받은 클래스명으로 입력해주면된다.
@Autowired
1.타입매칭
2.타입 매칭의 결과가 2개이상일때 필드명, 파라미터 명으로 빈 이름매칭
@Quilifier("mainDiscountPolicy")
클래스 바로 위에
@Quilifier("fixDiscountPolicy")
이런식으로 선언해줄수있다.
그러면 그 클래스에 빈에 등록된것을 가져다가 등록해준다.
public OrderServiceImpl(MemberRepository memberRepository, @Quilifier("fixDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Quilifier
는
@Quilifier로 선언된 녀석만 찾아서 쓰자
우선순위를 지정하는방식이다.
먼저 선택되게 하고싶은 클래스에 위에
@Primary
를 추가해주면된다.
@Primary, @Quilifier활용
메인 데이터베이스의 커넥션을 획득하는 스프링빈은 @Primary를
적용하여 조회하는곳에서는 지정없이 조죄하고
서브 데이터베이스에서 커넥션 빈을 획득하는 곳에서는 @Quilifier를 지정하여 명시적으로 획득하는 방식으로 사용하면 깔끔하다고 한다.
우선순위는
좁은 범위의 선택권 우선순위가 높기때문에
@Quilifier가 우선권이 더 높다.