[스프링 핵심원리 기본편] 스프링 컨테이너와 스프링 빈

흑수·2022년 1월 31일
0

김영한씨의 스프링 핵심 원리 - 기본편 강의를 듣고 공부 겸 정리하는 글입니다.

스프링 컨테이너 생성

// 스프링 컨테이너 생성
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class)

ApplicationContext를 스프링 컨테이너라고 합니다. 이는 인터페이스로서, AnnotationConfigApplicationContext가 구현체가 됩니다.

스프링 컨테이너는 XML을 기반으로도 만들 수 있고 위와 같이 자바 설정 클래스(AppConfig.class)로도 만들 수 있습니다.

과정

  1. 스프링 컨테이너 생성
  • 스프링 컨테이너를 생성하기 위해 구성정보를 지정해줍니다.
  • 스프링 컨테이너 내에 스프링 빈 저장소가 존재하고, 빈 이름과 빈 객체로 이루어집니다.
  1. 스프링 빈 등록
  • 설정 클래스 정보를 읽어서 @Bean을 확인하며 빈 저장소에 등록합니다.
  • 이 때, 빈 이름은 메소드 이름으로 대체되나, @Bean(name="memberService2")과 같이 직접 할당할 수도 있습니다.

AppConfig

@Bean
public MemberService memberService() {
    return new MemberServiceImpl(memberRepository());
}

@Bean
public MemberRepository memberRepository() {
    return new MemoryMemberRepository();
}

@Bean
public OrderService orderService() {
    return new OrderServiceImpl(memberRepository(), discountPolicy());
}

@Bean
public DiscountPolicy discountPolicy() {
    return new FixDiscountPolicy();
}
빈 이름빈 객체
memberServiceMemberServiceImpl@x01
memberRepositoryMemoryMemberRepository@x02
orderServiceOrderServiceImpl@x03
discountPolicyFixDiscountPolicy@x04
  1. 스프링 의존 관계 설정
  • 위를 토대로 의존 관계를 설정하게 된다.
  • memberService, orderService -> memberRepositroy
  • orderService -> discountPolicy

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

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 + " bean = " + bean);
        }
    }

    @Test
    @DisplayName("애플리케이션 빈 출력하기")
    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 + " bean = " + bean);
            }
        }
    }
}

ac.getBeanDefinitionNames : 스프링에 등록된 모든 빈 이름 조회
ac.getBean() : 빈 이름으로 빈 객체 조회

아래의 ROLE_APPLICATION을 이용하면 내가 등록한 빈만 조회할 수 있습니다.

스프링 빈 조회

스프링 빈을 조회하는 세 가지 경우를 소개하겠습니다.

기본

  • ac.getBean(빈이름, 타입)ac.getBean(타입)으로 조회할 수 있습니다.
// 빈 이름으로 조회
MemberService memberService = ac.getBean("memberService", MemberService.class);
// 이름 없이 타입으로 조회
MemberService memberService = ac.getBean(MemberService.class);
// 구체 타입으로 조회
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);

동일한 타입이 둘 이상

  • 타입으로 조회시 동일한 타입이 둘 이상일 때는 오류가 발생합니다.
  • 이런 경우에는 빈 이름을 지정해줍시다!
@Configuration
static class SameBeanConfig {
    @Bean
    public MemberRepository memberRepository1() {
        return new MemoryMemberRepository();
    }

    @Bean
    public MemberRepository memberRepository2() {
        return new MemoryMemberRepository();
    }
}
// 이름으로 직접 지정
MemberRepository memberRepository1 = ac.getBean("memberRepository1", MemberRepository.class);
// 특정 타입 모두 조회
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
for (String key: beansOfType.keySet()) {
    System.out.println("key = " + key + " value = " + beansOfType.get(key));
}

상속 관계

  • 부모를 조회하면 자식도 함께 조회합니다.
  • 그렇기 때문에 부모 조회시 자식이 둘 이상이면 오류가 발생합니다.

BeanFactory와 ApplicationContext

AnnotationConfigApplicationContext -> ApplicationContext(interface) -> BeanFactory(interface)

BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스
  • 스프링 빈을 관리, 조회 (getBean 등 제공)

ApplicationContext

  • BeanFactory 상속
  • 상속을 받는다면 존재 이유가 무엇일까? (관리, 조회 외에 수 많은 기능들 필요)
    -> MessageSource, EnvironmentCapable,... 등의 인터페이스 상속

정리
ApplicationContext는 BeanFatory를 상속함과 동시에 다른 부가 기능도 지원 받습니다. BeanFactory를 이용할 일이 거의 없고, 이 둘을 모두 스프링 컨테이너라고 부릅니다.

다양한 설정 형식 지원 - 자바 코드, xml

위에서 구성 설정 파일로 자바 코드를 넘겨 주었는데, 그 외에도 xml 등 설정이 가능합니다. 다만, 요새는 레거시 코드를 제외한 대부분이 자바 코드로 이루어졌기 때문에 자바 코드로 작성하면 됩니다.

xml을 설정한다면 GenericXmlApplicationContext을 이용해서 넘겨주면 된답니다.

스프링 빈 설정 메타 정보 - BeanDefinition

이렇게 다양한 설정 방식을 지원하게끔 도와주는 것이 BeanDefinition입니다. 이는 추상화로서, 역할구현을 개념적으로 나누었다는 이야기입니다.

profile
기록용

0개의 댓글