"인프런의 스프링 핵심원리 - 기본편 강의를 듣고 작성한 글 입니다."
스프링 컨테이너 생성
스프링 컨테이너가 생성되는 과정을 알아보자.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
- ApplicationContext 를 스프링 컨테이너라 한다. 여기서 ApplicationContext 는 인터페이스 이다.(다형성이 적용되어 있다는 뜻)
- 스프링 컨테이너는 XML 을 기반으로 만들 수 있고, 어노테이션 기반의 자바 설정 클래스(AppConfig) 로도 만들 수 있다.
- 직전에 AppConfig 를 사용했던 방식이 어노테이션 기반의 자바 설정 클래스로 스프링 컨테이너를 만든 것이다.
- 자바 설정 클래스를 기반으로 스프링 컨테이너(ApplicationContext) 를 만들어보자.
- new AnnotationConfigApplicationContext(AppConfig.class);
- 이 클래스는 ApplicationContext 인터페이스의 구현체이다.
+ 참고 : 더 정확히는 스프링 컨테이너를 부를 때 BeanFactory, ApplicationContext 로 구분해서 이야기한다. 이 부분은 뒤에서 더 설명한다. BeanFactory 를 직접 사용하는 경우는 거의 없으므로 일반적으로 ApplicationContext 를 스프링 컨테이너라 한다.
1. 스프링 컨테이너 생성
- 아래의 코드를 통해 스프링 컨테이너가 만들어진다.
new AnnotationConfigApplicationContext(AppConfig.class);
- 스프링 컨테이너를 생성할 때는 구성 정보를 지정해 주어야 한다.
- 여기서는 AppConfig.class 를 구성 정보로 지정했다.
2. 스프링 빈 등록
- 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록한다.
- 여기서 (빈 이름, 빈 객체) 의 형태로 스프링 빈이 저장소에 저장되는데, 빈 이름이 키(key) 의 역할을 하고, 빈 객체는 값(value) 의 역할을 한다.
* 빈 이름
- 빈 이름은 객체 인스턴스를 반환하는 메소드의 이름을 사용한다.
- 빈 이름을 직접 부여할 수도 있다.(@Bean(name = "memberService2"))
+ 주의 : 빈 이름은 항상 다른 이름을 부여해야 한다. 같은 이름을 부여하면 다른 빈이 무시되거나, 기존 빈을 덮어버리거나, 설정에 따라 오류가 발생한다.
3. 스프링 빈 의존관계 설정 - 준비
- 각 스프링 빈 들에게 의존관계를 맺어줄 준비를 한다.
4. 스프링 빈 의존관계 설정 - 완료
- 스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입(DI) 한다.
- 단순히 자바 코드를 호출하는 것 같지만 차이가 있다. 이 차이는 뒤에 싱글톤 컨테이너 에서 알아보자.
+ 참고 : 스프링 빈을 생성하고, 의존관계를 주입하는 단계가 나누어져 있다. 그런데 이렇게 자바 코드로 스프링 빈을 등록하면 생성자를 호출해서 의존관계 주입도 한번에 처리된다.
여기서는 이해를 돕기 위해 개념적으로 나누어 설명했다. 자세한 내용은 의존관계 자동 주입에서 다시 설명한다.
정리
스프링 컨테이너를 생성하고, 설정(구성) 정보를 참고해서 스프링 빈도 등록하고, 의존관계도 설정했다.
이제 스프링 컨테이너에서 데이터를 조회해보자.
컨테이너에 등록된 모든 빈 조회
스프링 컨테이너에 실제 스프링 빈 들이 잘 등록되어 있는지 확인해보자.
test 폴더의 hello.core 패키지 아래에 beanfind 패키지를 만들고 아래의 클래스를 작성하자.
- ApplicationContextInfoTest.java
public class ApplicationContextInfoTest {
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);
}
}
}
위의 코드를 출력하면 아래와 같은 결과를 얻을 수 있다.
name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor object = org.springframework.context.annotation.ConfigurationClassPostProcessor@600b9d27
name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor object = org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@3688eb5b
name = org.springframework.context.annotation.internalCommonAnnotationProcessor object = org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@69f1a286
name = org.springframework.context.event.internalEventListenerProcessor object = org.springframework.context.event.EventListenerMethodProcessor@7922d892
name = org.springframework.context.event.internalEventListenerFactory object = org.springframework.context.event.DefaultEventListenerFactory@457c9034
name = appConfig object = hello.core.AppConfig$$EnhancerBySpringCGLIB$$2dfd6684@345f69f3
name = memberService object = hello.core.member.MemberServiceImpl@50de186c
name = orderService object = hello.core.order.OrderServiceImpl@3f57bcad
name = memberRepository object = hello.core.member.MemoryMemberRepository@1e8b7643
name = discountPolicy object = hello.core.discount.RateDiscountPolicy@51549490
여기서 appConfig 위에 생성된 빈 들은 스프링에서 자체적으로 필요한 빈들을 내부에서 만들어낸 것이다.
그런데 만약 AppConfig 를 통해 생성된 스프링 빈만 출력하고 싶다면 어떻게 하는게 좋을까?
아래와 같은 코드를 추가하자.
- ApplicationContextInfoTest.java
public class ApplicationContextInfoTest {
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("name = " + beanDefinitionName + " object = " + bean);
}
}
// 직접 생성한 빈만 출력하는 코드
@Test
@DisplayName("애플리케이션 빈 출력하기")
void findApplicationBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames){
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
// 스프링에서 자체적으로 생성한 빈이 아니라, 직접 생성한 빈을 출력한다.(ROLE_APPLICATION)
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + " object = " + bean);
}
}
}
}
결과 :
name = appConfig object = hello.core.AppConfig$$EnhancerBySpringCGLIB$$2dfd6684@600b9d27
name = memberService object = hello.core.member.MemberServiceImpl@3688eb5b
name = orderService object = hello.core.order.OrderServiceImpl@69f1a286
name = memberRepository object = hello.core.member.MemoryMemberRepository@7922d892
name = discountPolicy object = hello.core.discount.RateDiscountPolicy@457c9034
출력을 보면 직접 생성한 스프링 빈만 출력되는 것을 확인할 수 있다.
* 모든 빈 출력하기의 경우
- 실행하면 스프링에 등록된 모든 빈 정보를 출력할 수 있다.
- ac.getBeanDefinitionNames() : 스프링에 등록된 모든 빈 이름을 조회한다.
- ac.getBean() : 빈 이름으로 빈 객체(인스턴스) 를 조회한다.
* 애플리케이션 빈 출력하기
- 스프링이 내부에서 사용하는 빈은 제외하고, 내가 등록한 빈만 출력해보자.
- 스프링이 내부에서 사용하는 빈은 getRole() 로 구분할 수 있다.
- ROLE_APPLICATION : 일반적으로 사용자가 정의한 빈
- ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈
다음 글에서부터는 스프잉 빈 조회의 상세 내용을 알아보자.
'Spring basic' 카테고리의 다른 글
스프링 핵심원리 : 기본편 - BeanDefinition 과 ApplicationContext (0) | 2022.02.13 |
---|---|
스프링 핵심원리 : 기본편 - 스프링 빈 조회 (0) | 2022.02.13 |
스프링 핵심원리 : 기본편 - IoC, DI, 그리고 컨테이너, 스프링으로 전환 (0) | 2022.02.11 |
스프링 핵심원리 : 기본편 - 새로운 구조와 할인 정책 적용, 그리고 정리 (0) | 2022.02.11 |
스프링 핵심원리 : 기본편 - 관심사의 분리 (0) | 2022.02.10 |