스프링 컨테이너 생성
ApplicationContext applicationContext = new
AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext가 스프링 컨테이너이다.
ApplicationContext는 인터페이스고, AnnotationConfigApplicationContext가 그 구현체이다.
스프링 컨테이너 만드는 방법
- 어노테이션 기반
- xml 기반(요즘은 잘 사용안함)
우리 예제에서는 AppConfig에 어노테이션을 붙여서 만들었다.
스프링 컨테이너를 생성할 때는 구성 정보를 지정해주야 한다. 여기서는 AppConfig.class 를 구성 정보로 지정했다.
스프링 빈은 빈 저장소에 @Bean이 붙은 애들을 등록한다. 보통은 메서드 이름이 빈 이름이지만 자신이 지정해 줄 수도 있다.
스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입(DI)한다.
컨테이너에 등록된 모든 빈 조회
테스트 코드에 beanfind 패키지-ApplicationContextInfoTest.java를 만들어 빈 조회를 테스트해보자.
class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(AppConfig.class);
}
스프링 컨테이너 구현체 ac를 하나 만들고 이것을 이용하여 모든 빈 출력, 애플리케이션 빈 출력을 테스트할 수 있다.
@Test
@DisplayName("모든 빈 출력하기")
void findAllBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name=" + beanDefinitionName + " object=" +
bean);
}
}
모든 빈 출력은 다음과 같이 작성하면 된다.
getBeanDefinitionNames()과 getBean() 함수를 활용한다.
스프링 내부 빈들 사이에 직접 등록한 빈 5개가 보인다. (appConfig, MemberService,OrderService....)
애플리케이션 빈 출력은 위 코드에
getBeanDefinition(beanDefinitionName).getRole()함수를 호출해 if문으로 걸러내서 호출하면 된다.
리턴값이 Role ROLE_APPLICATION이면 직접 등록한 애플리케이션 빈이고, Role ROLE_INFRASTRUCTURE이면 스프링이 내부에서 사용하는 빈이다.
스프링 빈 조회- 기본
가장 기본적인 빈 조회 방법
- getBean(빈이름,타입)
- getBean(타입)
MemberService memberService = ac.getBean("memberService", MemberService.class);
빈 이름으로 조회
MemberService memberService = ac.getBean(MemberService.class);
타입만으로 조회
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
구체 타입으로 조회(유연성 떨어짐)
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () ->
ac.getBean("xxxxx", MemberService.class));
조회대상 빈이 없으면 예외가 발생한다.
스프링 빈 조회 - 동일한 타입이 둘 이상
class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(SameBeanConfig.class);
...
//타입 조회시 중복 오류 확인하기 위해 내부 클래스로 하나 만듦
@Configuration
static class SameBeanConfig {
@Bean
public MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
}
중복인 경우 조회 결과를 확인하기 위해 내부 클래스로 스프링 컨테이너를 하나 만들자.
assertThrows(NoUniqueBeanDefinitionException.class, () ->
ac.getBean(MemberRepository.class));
타입으로 조회했는데 동일 타입의 빈이 둘 이상이면 오류가 발생한다.
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
이 경우 빈 이름을 지정하거나 getBeanOfType로 해당 타입의 모든 빈을 조회한다.
스프링 빈 조회 - 상속 관계
부모타입으로 조회하면 자식 타입도 함게 조회한다.
예를 들어 Object 타입으로 조회하면 모든 스트링 빈을 다 출력한다.
@Configuration
static class TestConfig {
@Bean
public DiscountPolicy rateDiscountPolicy() {
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy() {
return new FixDiscountPolicy();
}
}
마찬가지로 조회 결과 확인 위해 테스트 코드 내부에 컨테이너를 하나 만든다.
assertThrows(NoUniqueBeanDefinitionException.class, () ->
ac.getBean(DiscountPolicy.class));
부모 타입으로 조회시 자식이 둘 이상이면 예외가 발생한다.
이 경우 빈 이름을 함께 지정해야 한다.
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));
}
부모 타입으로 모두 조회할 수 있다.
부모 자신인 DiscoutPolicy가 출력되지 않은 이유는 빈 등록이 안되어서 인듯...
참고로 지금은 확인하려고 이렇게 하는데 테스트 코드에 출력문 넣는건 좋은 방법이 아니라고 한다.
BeanFactory와 ApplicationContext
BeanFactoy라는 최상위 인터페이스가 있고, 그를 상속하는 ApplicationContext 인터페이스가 있고, 그 밑에 우리가 사용했던 AnnotationConfigApplicationContext가 있다...
BeanFactoy
- 스프링 빈을 관리하고 조회하는 역할
- getBean등 지금까지 사용했던 대부분의 기능은 빈팩토리가 제공
ApplicationContext
- BeanFactory 기능을 모두 상속받아서 제공
- 그 외 많은 부가기능(환경변수, 리소스 조회 등)들을 제공
스프링 빈 설정 메타 정보 - BeanDefinition
초반에, 스프링 컨테이너 만드는 방법에는 여러가지가 있다고 언급했다.(어노테이션,xml)
BeanDefinition(=빈 설정 메타정보)
이라는 추상화 덕분에 스프링이 다양한 설정 형식을 지원할 수 있는 것이다.
어노테이션의 경우 @Bean, xml의 경우 <bean> 당 하나씩 메타 정보가 생성된다.
스프링 컨테이너는 이 메타정보를 기반으로 스프링 빈을 생성한다. 스프링 컨테이너는 자바 코드인지, XML인지 몰라도 된다. 오직 BeanDefinition만 알면 스프링 빈을 생성할 수 있다.
이 포스팅은 인프런 김영한님의 '스프링 핵심 원리 기본편'을 듣고 정리한 것입니다.
강의 링크: https://url.kr/udopsk
'개발 관련 공부 > 스프링 김영한 로드맵' 카테고리의 다른 글
[스프링 기본] 6. 컴포넌트 스캔 (0) | 2022.10.12 |
---|---|
[스프링 기본] 5. 싱글톤 컨테이너 (0) | 2022.10.12 |
[스프링 기본] 3. 스프링 핵심 원리 이해2 -객체 지향 원리 작용 (0) | 2022.10.10 |
[스프링 기본] 2. 스프링 핵심 원리 이해1-예제 만들기 (0) | 2022.10.07 |
[스프링 기본] 1. 객체 지향 설계와 스프링 (0) | 2022.10.05 |
댓글