스프링 컨테이너 생성
// 컨테이너 사용
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
- ApllicationContext를 스프링 컨테이너라 하며, 인터페이스이다.
- XML을 기반으로 만들 수 있고, 어노테이션 기반의 자바 설정 클래스로 만들 수 있다.
- AppConfig를 사용했던 방식이 어노테이션 기반의 자바 설정 클래스로 스프링 컨테이너를 만든 것이다.
- new AnnotationConfigApllicationContext(AppConfig.class)
- 스프링 컨테이너를 생성할 때는 구성 정보를 지정 해주어야 한다.
- 여기서는 AppConfig.class를 구성정보로 지정했다.
스프링 빈 등록
- 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 빈을 등록한다.
- 빈 이름은 메서드 이름을 사용하며, 직접 부여도 가능하다.
- 직접 부여는 @Bean(name="빈이름")
- 빈 이름은 항상 다른 이름을 부여해야 한다. 같은 이름을 부여하면, 다른 빈이 무시되거나, 기존 빈을 덮어버리거나 설정에 따라 오류가 발생한다.
스프링 빈 의존관계 설정
스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입(DI)한다.
단순히 자바 코드를 호출 하는 것 같지만, 이 차이는 싱글톤 컨테이너(포스팅 중에 다룰 예정입니다.)에 있다.
스프링은 빈을 생성하고, 의존관계를 주입하는 단계가 나누어져 있다. 스프링 컨테이너를 생성하고, 설정(구성) 정보를 참고해서 스프링 빈을 등록, 의존관계를 설정했다.
스프링 빈 조회하기
모든 빈 조회
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 ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
//Role ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + "Object = " + bean);
}
}
}
}
getBeanDefinitionNames() | 현재 CONTEXT에 등록된 모든 빈의 이름을 문자열 배열로 반환 |
getBean() | 빈 이름으로 빈 객체(인스턴스)를 조회한다. |
ROLE_APPLICATION | 사용자가 정의한 빈 |
ROLE_INFASTRUCTURE | 스프링이 내부에서 사용하는 빈 |
스프링이 내부에서 사용하는 빈은 getRole()로 하나식 꺼내볼 수 있다.
기본 조회
public class ApplicationContextBasicFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 이름으로 조회")
void findBeanByName() {
MemberService memberService = ac.getBean("memberService", MemberService.class);
System.out.println("memberService = " + memberService);
assertThat(memberService).isInstanceOf(MemberService.class);
}
@Test
@DisplayName("이름없이 타입으로만 조회")
void findBeanByType() {
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberService.class);
}
@Test
@DisplayName("구체 타입으로 조회")
void findBeanByName2() {
MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberService.class);
}
@Test
@DisplayName("빈 이름으로 조회X")
void findBeanByNameX() {
// ac.getBean("xxxxx", MemberService.class);
// MemberService xxxxx = ac.getBean("xxxxx", MemberService.class);
/* 빈조회가 실패할 테스트 케이스를 넣었을 때, NoSuchBeanDefinitionException 가 터져야 성공적인 테스트*/
assertThrows(NoSuchBeanDefinitionException.class,
() -> ac.getBean("xxxxx", MemberService.class));
}
}
- 스프링 컨테이너에서 스프링 빈을 찾는 가장 기본적인 조회 방법
- ac.getBean(빈이름, 타입)
- ac.getBean(타입)
조회 대상 스프링 빈이 없으면 예외가 발생한다.
NosuchBeanDefinitionException: No bean named 'xxxxx' available
동일한 타입이 둘 이상일 때의 조회
public class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다.")
void findBeanByTypeDuplicate(){
// MemberRepository bean = ac.getBean(MemberRepository.class);
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(MemberRepository.class));
}
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면, 빈 이름을 지정하면 된다.")
void findBeanByName() {
MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);
assertThat(memberRepository).isInstanceOf(MemberRepository.class);
}
@Test
@DisplayName("특정 타입을 모두 조회하기")
void findAllBeanByType(){
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
System.out.println("beansOfType" + beansOfType);
assertThat(beansOfType.size()).isEqualTo(2);
}
@Configuration
static class SameBeanConfig {
@Bean
public MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
}
타입으로 조회시 같은 타입의 스프링 빈이 둘 이상이면 예외가 발생한다. 이때는 빈 이름을 지정하면 된다.
ac.getBeansOFType()을 사용하면 해당 타입의 모든 빈을 조회 가능하다.
상속 관계 조회
부모 타입으로 조회하면, 자식 타입도 함께 조회한다.
모든 자바 객체의 최고 부모인 Object타입으로 조회하면, 모든 스프링 빈을 조회한다.
테스트 과정을 위 그림에 빗대어 말하자면
1번 : DiscountPolicy
2번 : RateDiscountPolicy
3번: FixDiscountPolicy
이렇게 테스트 하였다.
public class ApplicationContextExtendsFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
@Test
@DisplayName("부모 타입으로 조히시, 자식이 둘 이상 있으면, 중복 오류가 발생한다.")
void findBeanByParentTypeDuplicate(){
// DiscountPolicy bean = ac.getBean(DiscountPolicy.class);
assertThrows(NoSuchBeanDefinitionException.class,
() -> ac.getBean(DiscountPolicy.class));
}
@Test
@DisplayName("부모 타입으로 조회시, 자식이 둘 이상 있으면, 빈 이름을 지정하면 된다.")
void findBeanByParentTypeBeanName(){
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("특정 하위 타입으로 조회")
void findBeanBySubType(){
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("부모 타입으로 모두 조회하기")
void findAllBeanByParentType(){
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));
}
}
@Test
@DisplayName("부모 타비으로 모두 조회하기 - Object")
void findAllBeanByObjectType(){
Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
// 실무에서는 출력을 자제하자.
}
}
@Configuration
static class TestConfig{
@Bean
public DiscountPolicy rateDiscountPolicy(){
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy(){
return new FixDiscountPolicy();
}
}
}
'Spring' 카테고리의 다른 글
Spirng Boot - REST API로 CRUD 만들기 (0) | 2024.04.03 |
---|---|
Spring Security 살펴보기 (0) | 2024.02.22 |
스프링 핵심 원리 - 예제 만들기 (0) | 2024.01.14 |
객체지향 설계와, 스프링 (1) | 2024.01.12 |
스프링 입문 - 스프링 웹 개발 기초 (1) | 2023.12.18 |