본 포스팅은 김영한님의 강의를 듣고 재구성하였습니다.
스프링 컨테이너의 생성
ApplicationContext -> 스프링 컨테이너
ApplicationContext -> Interface
스프링 컨테이너는 애노테이션기반의 자바클래스 뿐만 아니라 XML을 기반으로 만들 수 있다.
방금 예제에서 Appconfing 를 사용했던 방식이 전자에 해당.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
new Annotaion~ 은 ApplicationContext의 구현체이다.
TMI) 더 정확히는 스프링 컨테이너를 부를 때 BeanFactory , ApplicationContext 로 구분해서 이야기한다. 이 부분은 뒤에서 설명하겠다. BeanFactory 를 직접 사용하는 경우는 거의 없으므로 일반적으로 ApplicationContext 를 스프링 컨테이너라 한다
- 스프링 컨테이너에는 스프링 Bean 저장소가 있음.
- key- Bean의 이름(method의 이름) value - Bean 객체
- 이 때 구성정보를 지정해주어야함 -> 여기서는 구성정보는 AppConfig.class
- 그러면 스프링이 구성정보를 보고 객체 생성해야 될 것들 해줌.
스프링 컨테이너는 @Bean 이 붙은것을 죄다 호출. 그래서 스프링 Bean으로 등록한다.
- Bean의 이름 == 메서드의 이름
- 직접 부여도 가능(@Bean = "memberService2")
- 주의) 빈 이름은 항상 다른 이름을 부여해야한다.
설정정보를 참고해서 의존관계를 주입한다.
단순 자바코드를 호출하는 것 같지만, 싱글톤 컨테이너에서 설명.
빈 조회하기
@Test
@DisplayName("애플리케이션 출력하기")
void findApplicationBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);//bean
//OLE_APPLICATION : 일반적으로 사용자가 정의한 빈
//ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈
if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){
Object bean = ac.getBean(beanDefinitionName);
System.out.println("beanDefinitionName = " + beanDefinitionName + "object " + bean);
}
}
}
ac.getBeanDefinitionNames(): 정의된 빈들의 key(이름)을 가져옴.
ac.getBean(빈 이름,타) : 빈 객체를 가져옴.
ac.getBeanDefinition(빈 이름): Bean의 메타데이터 정보를 가져옴. getrole()을 통해 직접만든 빈을 구분하기 위해 사용.
@Test
@DisplayName("빈 이름으로 조회")
void findBeanByName(){
MemberService memberService = ac.getBean("memberService", MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);//인터페이스면 구현되어있는 객체를 반환.
}
@Test
@DisplayName("이름없이 빈 타입으로 조회")
void findBeanByType(){
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("구체 타입으로 조회")
void findBeanByType2(){
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈이름으로 조회X")
void findBeanByNameX(){
//ac.getBean("xxxx",MemberService.class);
assertThrows(NoSuchBeanDefinitionException.class,
()-> ac.getBean("xxxx",MemberService.class)); // 뒤에있는 행동을 하면 앞에있는 예외가 터져야한다.
}
junit의 assertThorws -> 이러한 예외가 나와야한다!
스프링 빈 조회 - 동일한 타입이 둘 이상
타입으로 조회시 같은 타입의 스프링 빈이 둘 이상이면 오류가 발생 -> 이름을 지정해주자.
ac.getBeanofType() -> 해당 타입의 모든 빈을 조회할 수 있다.
클래스 안에 클래스 -> 클래스 안에서만 쓰겠다.
스프링 빈 조회 - 상속 관계
부모 타입으로 조회하면 자식 타입도 함께 조회한다.
그래서 모든 자바 객체의 최고부모인 Object 타입으로 조회하면, 모든 빈을 조회한다.
BeanFactory와 ApplicationContext
BeanFactory
스프링 컨테이너의 최상위 인터페이스
스프링을 곤리하고 조회하는 역할 담당
getBean()제공
지금까지 사용한 것의 대부분의 기능은 BeanFactory가 제공하는 기능.
ApplicationContext
BeanFactory 기능을 모두 상속받아 제공
빈을 관리하고 검색하는 기능을 빈팩토리가 제공해줌.. 그럼 둘의 차이는뭘까?
애플리케이션 개발할 때는 빈 관리, 조회 기능뿐아니라 수많은 부가기능이 필요.
MessageSource : 이것을 활용한 국제화 기능. ex) 한국어로 들어오면 한국어로, 영어권에서 들어오면 영어로 출력.
EnvironmentCapable(환경변수): 로컬, 개발 , 운영 등을 구분해서 처리
ApplicationEventPublisher: 이벤트를 발행하고 구독하는 모델을 편리하게 지원
ResourceLoader: 파일, 클래스패스,외부 등에서 리소스를 편리하게 조회
정리
ApplicationContext 는 BeanFactory의 기능을 상속받는다.
ApplicationContext는 빈관리기능 + 편리한 부가 기능을 제공한다.
BeanFactory를 직접사용할일은 거의 없고 ApplicationContext 를 사용한다.
BeanFactory나 ApplicationContext를 스프링 컨테이너라 한다.
다양한 설정형식 지원 ex) 자바코드, XML 등
XML 설정 사용
많은 레거시 프로젝트들이 XML로 되어있고, 또 XML을 사용하면 컴파일 없이 빈설정정보를 변경할 수 있는 장점도 있다.
GenericXmlApplicationContext를 사용하면서 xml설정 파일을 넘기면된다.
스프링 빈 설정 메타 정보 - BeanDefinition
빈정보 -> BeanDefinition이라는 추상화가 있어 이용.
쉽게 이야기해 역할과 구현을 개념적으로 나눈것.
xml 읽고 BeanDefinition 만듦.
자바 코드 읽고 BeanDefinition 만듦.
BeanDefinition -> bean 설정 메타정보라고 함. @Bean <bean> 각각 하나씩 메타정보가 생성.
스프링컨테이너는 이메타정보를 기반으로 스프링 빈 생성.
1. AnnotationConfigApplicationContext는 AnnotatedBeanDefinitionReader를 이용해 AppConfig.class를 읽음.
2. BeanDefinition(빈메타정보 생성)
BeanDefinition 정보
BeanClassName: 생성할 빈의 클래스 명(자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음)
factoryBeanName: 팩토리 역할의 빈을 사용할 경우 이름, 예) appConfig
factoryMethodName: 빈을 생성할 팩토리 메서드 지정, 예) memberService
Scope: 싱글톤(기본값)
lazyInit: 스프링 컨테이너를 생성할 때 빈을 생성하는 것이 아니라, 실제 빈을 사용할 때 까지 최대한 생성을 지연처리 하는지 여부
InitMethodName: 빈을 생성하고, 의존관계를 적용한 뒤에 호출되는 초기화 메서드 명
DestroyMethodName: 빈의 생명주기가 끝나서 제거하기 직전에 호출되는 메서드 명
Constructor arguments, Properties: 의존관계 주입에서 사용한다. (자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음)
정리
BeanDefinition을 직접 생성해서 스프링컨테이너에 등록할 수 도 있음. 그러나 실무에서 직접정의하거나 사용할일은 거의 없음.
BeanDefitnition에 대해서는 너무 깊이있게 이해하기 보다는, 스프링의 다양한 형태의 설정 정보를 BeanDefinition으로 추상화해서 사용하는 것 정도만 이해하면 된다.
스프링에서 빈을 등록하는 방법.
1. 직접 스프링빈을 등록하는 방법
2. 팩토리 메서드를 이용해 등록하는 방법(약간 우회해서하는방법) 외부에서 메서드를 호출하면 생성이 되는 방식.
자바코드로 등록 -> 팩토리메서드를 이용해서 등록.
'Spring > 스프링 원리 - 기본편' 카테고리의 다른 글
[스프링-기본] 섹션 6. 컴포넌트 스캔 (0) | 2023.01.24 |
---|---|
[스프링-기본] 섹션5. 웹 애플리케이션과 싱글턴 (0) | 2023.01.23 |
[스프링-기본] 섹션2,3 스프링 핵심 원리 이해 (1) | 2023.01.19 |
[스프링-기본] 섹션1. 객체 지향 설계와 스프링 (0) | 2023.01.18 |