스프링 컨테이너와 스프링 빈 조회

jaepani5015·2021년 4월 19일
0

Spring 공부 정리

목록 보기
1/10

스프링 컨테이너란?

스프링 컨테이너는 Bean들의 생명주기를 관리한다. 또한 어플리케이션을 구성하는 모든 Bean들을 관리하기 위해 IoC를 사용한다.

스프링 컨테이너의 종류에는 BeanFactory와 이를 상속한 ApplicationContext가 있다.
이 두개의 컨테이너로 의존성 주입된 빈들을 제어하고 관리할 수 있다.

스프링 컨테이너 생성

스프링 컨테이너를 생성하기 위해서는 여러 방법이 있는데 그 중에 어노테이션 방식을 지원하는 AnnotationApplicationContext를 사용해본다.

ApplicationContext ac = new AnnotationApplicationContext(AppConfig.class);

ApplicationContext는 스프링 컨테이너 이면서 동시에 인터페이스 이다.
AnnotationApplicationContextApplicationContext의 구현체 중 하나이며, AppConfig.class를 구성정보로 활용하는데 AppConfig.class에 있는 메소드 들을 스프링 빈으로 생성한다.

스프링 컨테이너 생성과정

생성과정은 다음 코드를 기준으로 한다.

ApplicationContext ac = new AnnotationApplicationContext(AppConfig.class);

1. 스프링 컨테이너 생성

  1. new AnnotationApplicationContext(AppConfig.class)에 의해서 스프링 컨테이너가 생성된다.
  2. 생성되면 스프링 컨테이너는 구성정보를 필수로 넣어주어야 한다. 그리고 넣어준 구성정보를 활용하게 되는데 현재는AppConfig.class 구성정보를 사용하고 있다.

AppConfig.class구성 정보는 @Configuration@Bean 어노테이션이 있는 설정관련 클래스이다. 해당 클래스를 통해서 의존성 주입과 같이 빈에 등록시킬 여러 설정이 되어있다.

2. 스프링 빈 등록

  • 스프링 컨테이너는 구성정보를 활용해 스프링 빈을 등록한다.
  • 기본 적으로 빈 이름은 메서드 명을 사용하며, 따로 빈 이름을 직접 부여할 수 있다.
  • 직접 빈 이름을 부여하는 방법은 다음처럼 해주면 된다. @Bean(name = "[설정할 빈 이름]")
    !!! 주의할 점은 빈 이름은 중복되면 안된다!!!

3. 스프링 빈 의존관계 설정 준비

  • 스프링 컨테이너의 스프링 빈 저장소에 등록된 빈들이 AppConfig.class에서 구성 정보에 따라 서로 의존관계가 되도록 준비한다.

4. 스프링 빈 의존관계 설정 완료

  • 스프링 컨테이너는 구성 정보를 참고해서 의존관계를 주입(DI) 한다.
  • 단순 자바 코드 호출과는 차이가 있으며, 이는 싱글톤에서 따로 설명한다.

컨테이너에 등록된 모든 빈 조회

스프링 컨테이너에 등록된 빈을 조회하기 위해서는 AnnotationConfigApplicationContext의 메소드인 getBeanDefinitionNames()를 사용해 모든 빈을 조회할 수 있다.

Test코드를 작성하여 등록된 빈을 조회해 보도록 한다.

등록된 빈 조회 코드

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

@Test
void findBean() {
	String[] beanDefinitionNames = ac.getBeanDefinitionNames();
	for (String beanDefinitionName : beanDefinitionNames) {
		Object bean = ac.getBean(beanDefinitionName);
		System.out.println("name = " + beanDefinitionName + " ::: object = " + bean);
	}
}

등록된 빈 조회 코드 결과

name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor ::: object = org.springframework.context.annotation.ConfigurationClassPostProcessor@6492fab5
name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor ::: object = org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@2c5529ab
name = org.springframework.context.annotation.internalCommonAnnotationProcessor ::: object = org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@39a8312f
name = org.springframework.context.event.internalEventListenerProcessor ::: object = org.springframework.context.event.EventListenerMethodProcessor@5f6722d3
name = org.springframework.context.event.internalEventListenerFactory ::: object = org.springframework.context.event.DefaultEventListenerFactory@2c532cd8
name = appConfig ::: object = hello.core.AppConfig$$EnhancerBySpringCGLIB$$dfa855fc@294e5088
name = memberRepository ::: object = hello.core.member.MemoryMemberRepository@51972dc7
name = discountPolicy ::: object = hello.core.discount.RateDiscountPolicy@3700ec9c
name = memberService ::: object = hello.core.member.MemberServiceImpl@2002348
name = orderService ::: object = hello.core.order.OrderServiceImpl@5911e990

결과를 보면 등록된 빈 이름과 빈 객체의 인스턴스 값을 확인할 수 있다.
하지만 결과에 AppConfig.class에 등록한 빈 뿐만 아니라 스프링 내부에서 사용하는 빈 까지 전부 출력된다.

만약 AppConfig.class 구성정보로 등록한 빈만 확인하기 위해서는 Role을 통해서 필터링을 해주면 된다.

구성정보(AppConfig.class)로 등록한 빈 조회 코드

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

@Test
void findApplicationBean() {
    String[] beanDefinitionNames = ac.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
        
        if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
            Object bean = ac.getBean(beanDefinitionName);
            System.out.println("name = " + beanDefinitionName + " ::: object = " + bean);
        }
    }
}

조회하는 과정에서 ac.getBeanDefinition(beanDefinitionName); 에서 값을 받아서 getRole() 메서드로 만약 RoleApplication이면 출력하도록 한다.

Role

  • ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
  • ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈

구성정보(AppConfig.class)로 등록한 빈 조회 코드 결과

name = appConfig ::: object = hello.core.AppConfig$$EnhancerBySpringCGLIB$$dfa855fc@6492fab5
name = memberRepository ::: object = hello.core.member.MemoryMemberRepository@2c5529ab
name = discountPolicy ::: object = hello.core.discount.RateDiscountPolicy@39a8312f
name = memberService ::: object = hello.core.member.MemberServiceImpl@5f6722d3
name = orderService ::: object = hello.core.order.OrderServiceImpl@2c532cd8

결과를 보면 구성정보로 등록한 빈만 출력되는 것을 확인할 수 있다.'

빈 기본 조회 방법

빈을 조회하는 방법은 ac.getBean(빈이름, 타입); 또는 ac.getBean(타입)으로 조회할 수 있다.
만약 조회할 대상이 없다면 NoSuchBeanDefinitionException 예외가 발생한다.

빈 이름으로 조회

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

@Test
void findBeanName() {
    MemberService memberService = ac.getBean("memberService", MemberService.class);
    assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}

빈 이름없이 타입으로 조회

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

@Test
void findType() {
    MemberService bean = ac.getBean(MemberService.class);
    assertThat(bean).isInstanceOf(MemberServiceImpl.class);
}

빈 조회 에러발생

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

@Test
void findBeanError() {
    assertThrows(NoSuchBeanDefinitionException.class, () -> ac.getBean("error", MemberService.class));
}

참고

READ

2021.04.19 - 첫 내용 작성

profile
LOVE JEJU🏝 :: 백엔드 개발자로 성장중... 💻

관심 있을 만한 포스트

0개의 댓글