Chapter 4. 스프링 컨테이너와 스프링 빈
스프링 컨테이너 생성
ApplicationContext(인터페이스)를 스프링 컨테이너라 한다.
XML 기반으로도 만들 수 있고, 에노테이션 기반의 자바 설정 클래스로도 만들 수 있다.
스프링 컨테이너 생성(AppConfig.class - 구성 정보) -> 스프링 컨테이너 (스프링 빈 저장소) -> 빈 이름, 빈 객체
빈 이름 | 빈 객체 |
memberService | MemberServiceImpl@x01 |
orderService | OrderServiceImpl@x02 |
memberRepository | MemoryMembmerRepository@03 |
빈 이름은 항상 다른 이름을 부여 해야 한다. 기존 빈을 덮어버리거나 설정에 따라 오류가 발생한다.
애매한 건 실무에서 사용하지 말자.
스프링 빈을 생성 한 뒤 설정 정보(AppConfig)를 참고해서 의존 관계를 주입(DI)함.
스프링의 경우 1. 빈 생성 2. 의존관계를 주입한다. 단계가 나뉘어 있음. (실제 LifeCycle)
자바 코드로 스프링 빈을 등록하면 의존 관계 주입도 한번에 처리 된다.
컨테이너에 등록된 모든 빈 조회
@Test
@DisplayName("애플리케이션 빈 출력하기")
void findApplicationBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
// ROLE_APPLICATION 직접 등록한 애플리케이션 빈
// ROLE_INFRASTRUCTURE: 스프링 내부에서 사용하는 빈
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + "object = " + bean);
}
}
}
스프링 빈 조회 - 기본
실패한 경우에 대한 테스트 코드도 잘 작성하자.
스프링 빈 조회 - 상속 관계
중요
부모 타입으로 조회하면, 자식 타입도 함께 조회한다.
부모 타입으로 조회 시, 자식이 둘 이상 있을 때 NoUniqueBeanDefinitionException 발생. 이런 경우에는 빈 이름을 지정하여 조회하거나 특정 구체 타입으로 조회한다.
BeanFactory와 ApplicationContext
BeanFactory
스프링 컨테이너 최상위 인터페이스
스프링 빈 관리 및 조회 역할
거의 직접 사용하지 않음
ApplicationContext
빈을 관리하고 검색하는 기능은 BeanFactory에서 제공하지만 그걸 상속 받아 모두 제공하고 부가 기능을 추가한다.
스프링 컨테이너
// 실제 ApplicationContext 클래스
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
}
MessageSource: 국제화 - 한국에서 들어오면 한국어, 영어권의 경우 영어
환경변수: 로컬, 개발, 운영 등 다양한 프로젝트 환경에 대해서 구분해서 처리 할 수 있게함
다양한 설정 형식 지원 - 자바 코드, XML
다양한 형식의 설정 정보를 받아드릴 수 있게 유연하게 설계되어 있음
AnnotationConfigApplicationContext (AppConfig.class) - 애노테이션 기반
// ApplicationContext 상속 받아서 사용 하는 것 확인 가능
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
}
GenericXmlApplicationContext (AppConfig.xml) - XML 설정 기반
스프링 부트 사용하면서 XML 기반 설정을 잘 사용하지 않게 됨.
하지만 아직 우리 회사 같이 레거시 프로젝트들은 xml로 많이 되어 있으니 배워두는 것이 좋다.
AppConfig.class에서
<bean id="orderService" class="hello.demo.order.OrderServiceImpl">
<constructor-arg name="memberRepository" ref="memberRepository"></constructor-arg>
<constructor-arg name="discountPolicy" ref="discountPolicy"></constructor-arg>
</bean>
XxxApplicationContext
다양하게 정의해서도 사용 할 수 있다.
스프링 빈 설정 메타 정보 - BeanDefinition
약간 교양 수업..
스프링이 어떻게 다양한 형식들로 설정 형식을 지원하는지는 BeanDefinition 추상화를 보면 알 수 있다.
스프링 컨테이너는 BeanDefinition(설정 메타 정보, (ex: @Bean, <bean>...)을 읽어서 스프링 빈을 생성한다.
실제 BeanDefinition은 인터페이스로 구현되어 있어서 스프링 컨테이너는 그냥 뭐로 구현되어있든 구현체(어노테이션 컨텍스트, Xml 컨텍스트...)에서 각각의 Bean에 대한 BeanDefinition만 맞춰주면 빈을 생성(BeanFactory) 할 수 있다.
public class GenericXmlApplicationContext extends GenericApplicationContext {
// XmlBeanDefinitionReader를 통해 appConfig.xml 문서를 읽고 BanDefinition 생성
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
}
AppConfig.class에 설정한 Bean에 대한 BeanDefinition 정보 출력
일단 지금은 이런 정보들이 있고 메타 정보들이 있다 라고 알아두자.
beanDefinitionName = memberService
beanDefinition = Root bean: class [null]; scope=(기본은 싱글톤); abstract=false; lazyInit=null(실제 사용하는 시점에서 빈 생성); autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appConfig; factoryMethodName=memberService; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in hello.demo.AppConfig
BeanDefinition을 직접 생성해서 스프링 컨테이너에 등록할 수 있지만 실무에서 사용 할 일 거의 없음.
appConfig.xml 출력 방식.
beanDefinitionName = memberService
beanDefinition = Generic bean: class [hello.demo.member.MemberServiceImpl]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null; defined in class path resource [appConfig.xml]
차이점
xml의 경우에는 스프링에 빈이 직접적으로 등록되는 것이고 어노테이션(자바 설정 파일)의 경우에는 factoryMethod .. 어짜고로 간접적으로 우회에서 등록함.
그래서 xml 쪽에서는 class가 명확하게 보이지만 어노테이션 쪽에서는 보이지 않는다.
'Spring' 카테고리의 다른 글
스프링 핵심 원리 기본편 - 챕터 6. 컴포넌트 스캔 (0) | 2023.03.19 |
---|---|
스프링 핵심 원리 기본편 - 챕터 5. 싱글톤 컨테이너 (0) | 2023.03.19 |
스프링 핵심 원리 기본편 - 챕터 3 (0) | 2023.03.10 |
스프링 핵심 원리 기본편 - 챕터 1,2 (0) | 2023.03.05 |
스프링 프로젝트 구조 알아보기 (0) | 2020.04.16 |
댓글