복습
스프링 컨테이너, 스프링 빈 본문
스프링 컨테이너 생성
//스프링 컨테이너 생성
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
- ApplicationContext를 스프핑 컨테이너라 한다.
- ApplicationContext는 인터페이스이다.
- 스프링 컨테이너는 XML을 기반으로 만들 수 있고, 애노테이션 기반의 자바 설정 클래스로도 만들 수 있다.
- AppConfig 방식이 애노테이션 기반의 자바 설정 클래스로 만든 것이다.
- 자바 설정 클래스를 기반으로 스프링 컨테이너(ApplicationContext)를 만들어보자.
- AnnotationConfigApplicationContext는 ApplicationContext 인터페이스의 구현체이다.
스프링 컨테이너 생성 과정
1. 스프링 컨테이너 생성
- 스프링 컨테이너를 생성할 때는 구성 정보를 지정해주어야 한다.
- 위의 코드를 보면 AppConfig.class를 생성자의 파라미터로 넘겨주었다.
2. 스프링 빈 등록
- 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용하여 스프링 빈을 등록한다.
- 빈 이름은 메서드 이름을 사용한다.
- @Bean(name="memberService2")의 형식으로 직접 빈 이름을 부여할 수도 있다.
빈 이름은 항상 다른 이름을 부여해야 한다.
같은 이름을 부여하면 다른 빈이 무시되거나, 기존 빈을 덮어버리는 등의 설정에 따라 오류가 발생!
3. 스프링 빈 의존관계 설정
- 스프링 컨테이너는 설정 정보를 참고하여 의존관계를 주입한다.
- 단순히 자바 코드를 호출하는 것 같지만, 차이가 있다. (이 차이는 싱글톤 컨테이너에서 설명)
- 스프링은 빈을 생성하고, 의존관계를 주입하는 단계가 나누어져 있지만
- 위의 방식처럼 자바 코드로 스프링 빈을 등록하면 생성자를 호출하면서 의존관계 주입도 한번에 처리된다.
컨테이너에 등록된 빈 조회
모든 빈 출력
void findAllBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name=" + beanDefinitionName + " object=" + bean);
}
}
- getBeanDefinitionNames 메서드를 이용하여 스프링에 등록된 모든 빈 이름을 조회한다.
- 가져온 빈 이름들을 이용하여 빈 객체 조회
애플리케이션 빈 출력
//Role ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
//Role ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name=" + beanDefinitionName + " object=" + bean);
}
- getRole 메서드를 사용하여 어떤 빈인지 구분한다.
- ROLE_APPLICATION: 일반적으로 사용자가 정의한 빈
- ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈
- 위의 코드는 ROLS_APPLICATION을 사용하여 사용자가 정의한 빈만 조회
스프링 빈 조회 - 기본
- 스프링 컨테이너에서 스프링 빈을 찾는 가장 기본적인 조회 방법으로 getBean(빈이름, 타입), getBean(타입)이 있다.
// 빈 이름으로 조회
void findBeanByName() {
MemberService memberService = ac.getBean("memberService", MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
// 타입으로 조회
void findBeanByType() {
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
- findBeanByName()에서는 빈 이름과 타입을 이용하여 조회
- findBeanByType() 에서는 타입으로만 조회(동일한 타입이 여러 개면 오류 발생)
// 구체 타입으로 조회
void findBeanByName2() {
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
// 존재하지 않는 빈 이름으로 조회
void findBeanByNameX() {
Assertions.assertThrows(NoSuchBeanDefinitionException.class,
() -> ac.getBean("xxxxx", MemberService.class));
}
- findBeanByName2() 에서 구현체 타입으로 조회(변경 시 유연성이 떨어짐)
- findBeanByNameX() 에서는 존재하지 않는 빈 이름으로 조회
- 조회 시 NoSuchBeanDefinitionException 예외가 발생한다.
- assertThat : 테스트 결과가 올바른 값이 나오는지 검사. (성공 테스트)
- assertThrows : 테스트 결과가 예외가 발생하는지 검사. (실패 테스트)
스프링 빈 조회 - 동일한 타입 둘 이상
- AnnotationConfigApplicationContext 객체 생성 시 동일한 타입의 메서드가 둘 이상 존재하는 클래스를 파라미터로 넘기면, 중복오류 발생
// 중복 오류 발생
void findBeanByTypeDuplicate() {
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(MemberRepository.class));
}
// 중복 오류를 막기 위해 빈 이름을 지정
void findBeanByName() {
MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);
assertThat(memberRepository).isInstanceOf(MemberRepository.class);
}
- 동일한 타입의 메서드가 둘 이상 존재하여 findBeanByTypeDuplicate()에서 타입으로 조회 시 NoUniqueBeanDefinitionException 예외 발생
- 중복 오류를 막기 위해 findBeanByName() 에서는 빈 이름을 지정해주어 중복 오류 방지
void findAllBeanByType() {
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
- getBeansOfType() 메서드를 이용하여 특정 타입의 빈을 모두 조회
스프링 빈 조회 - 상속 관계
- 부모 타입으로 조회하면, 자식 타입도 함께 조회한다.
- 모든 자바 객체의 최고 부모인 Object 타입으로 조회하면, 모든 스프링 빈을 조회함.
// 부모 타입으로 조회 시, 자식이 둘 이상이면 중복 오류 발생
void findBeanByParentTypeDuplicate() {
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(DiscountPolicy.class));
}
// 중복 오류를 막기 위해 빈 이름 지정
void findBeanByParentTypeBeanName() {
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}
- 부모 타입으로 조회 시 자식 타입도 함께 조회하는데, 이때 조회된 자식이 둘 이상이면 중복 오류 발생
- 위에서와 마찬가지로 중복 오류를 막기 위해 빈 이름을 지정한다.
- 특정 하위 타입으로 조회, 부모 타입으로 모두 조회도 위에서와 같은 방식으로 구현
출처
스프링 핵심 원리 - 기본편 - 인프런 | 강의
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...
www.inflearn.com
'Spring뿌시기 > 3주차 - 스프링 핵심 원리 기본편 2' 카테고리의 다른 글
싱글톤 컨테이너 - @Configuration과 싱글톤 (0) | 2022.10.24 |
---|---|
싱글톤 컨테이너 - 싱글톤 컨테이너 (0) | 2022.10.24 |
싱글톤 컨테이너 - 싱글톤 패턴 (0) | 2022.10.24 |
스프링 컨테이너 설정 - 자바 코드, XML / 스프링 빈 메타 정보BeanDefinition (0) | 2022.10.19 |
BeanFactory와 ApplicationContext (0) | 2022.10.19 |