https://www.inflearn.com/roadmaps/373
컨테이너의 생성과정
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
인터페이스인 ApplicationContext를 스프링 컨테이너라고 한다.
그리고 AnnotationConfigApplicationContext는 ApplicationContext의 구현체이다.
스프링 컨테이너는 xml, 애노테이션 기반의 자바 설정 클래스로 만들 수 있다.
2편에서 살펴본 방식은 @Configuration을 통한 애노테이션으로 스프링 컨테이너를 만든 것이다.
new AnnotationConfigApplicationContext(구성(설정)정보 지정)
⟹ new AnnotationConfigApplicationContext(AppConfig.class)
(AppConfig클래스에는 @Configuration어노테이션이 적용되어 있다. 그래서 설정 정보로 사용이 가능하다.)
⟹ 그리고 이제 AppConfig.class에 @Bean이 적용되어 있는 객체들을 스프링 빈으로 등록한다.
💥주의사항 : Bean이름은 보통 메서드 이름을 사용하는 것이 관례이지만, Bean(name="내맘이다") 이런 방식으로 이름을 부여할 수 있지만, 이왕이면 관례를 따르는 것이 좋다.
💣 그럼에도 불구하고 사용해야 하는 경우에는, 같은 이름을 부여하게 된다면, 기존의 Bean을 덮어버리거나 설정에 따라 오류가 발생할 수 있다.
의존관계 설정
👉흐름 : 스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입한다.
memberService는 저장소만 필요하기 때문에 memberRepository만을 의존하고,
orderService 같은 경우 저장소, 할인 정책 두 가지가 다 필요하기 때문에, memberRepository+discountPolicy 모두 의존한다.
이런 방식으로 등록한 빈을 조회하는 방법
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); @Test @DisplayName("빈 조회방법") void findBean(){ String[] beanDefinitionNames = ac.getBeanDefinitionNames(); for(String beanDefinitionNames = beanDefinitionNames){ BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionNames); if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){ Object bean = ac.getBean(beanDefinitionName); System.out.println("name은 ="+beanDefinitionName+" /object 부분은 ="+ bean); } } }
ac.getBeanDefinitionNames() : 스프링에 등록된 모든 빈 이름을 조회해준다.
ROLE_APPLICATION : 일반적으로 사용자가 정의한 빈(ex. discountPolicy, memberRepository)
ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈
:: 실제 개발시에는 BeanNullPoint가 뜰 때 어떤 Bean이 들어있는지 확인할 때 사용한다.
자주 사용하는 편은 아니라고 한다.**
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class)
1. 빈 이름+타입으로 조회 void findBeanName(){ MemberService memberService = ac.getBean("memberService", MemberService.class); assertThat(memberService).isInstanceOf(MemberServiceImpl.class); // memberService가 MemberServiceImpl의 인스턴스이면 테스트 성공 } 2. 오직 타입으로만 조회 void findBeanType(){ MemberService memberService = ac.getBean(MemberService.class); assertThat(memberService).isInstanceOf(MeberServiceImpl.class); } 3. 조회가 안되는 경우(실패 테스트) void findBeanX(){ Assertions.assertThrows(NoSuchBeanDefinitionException.class, () ⟶ ac.getBean("xx", MemberService.class)); } //ac.getBean부분이 없으면 NoSuchBeanDefinitionException에러가 터질 것이고, 그 에러가 터지면 테스트는 성공!
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class) // 부모 타입으로 조회시, 자식이 둘 이상 있으면, 빈 이름을 지정하면 된다 void findBeanByParentTypeBeanName(){ DisCountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class); assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class); } // 특정 하위 타입으로 조회 : RateDiscountPolicy void findBeanType(){ RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class); assertThat(bean).isInstanceOf(RateDiscountPolicy.class); } // 부모 타입으로 조회하기 : DiscountPolicy void findParentType(){ 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)); } }
➽ 이번에는 가볍게 스프링 컨테이너의 생성과정과 그 안에 빈들을 조회하는 방법을 정리했다.
빈을 조회하는 경우는 BeanNullPoint상황에 사용한다고 하는데, 그런 경우가 흔하지는 않다고 하지만, 생성과정과 이런 조회하는 방법 또한 숙지해놓으면 좋을 것 같다.