Programming/Spring

[Spring] BeanDefinition

Supreme_YS 2022. 2. 7. 12:25

 

 

[Spring] 스프링 빈 조회

스프링 빈을 조회하는 다양한 방법에 대해 코드로 살펴보자. * BeanFactory BeanFactory는 스프링 컨테이너의 최상위 인터페이스 스프링 빈을 관리하고 조회하는 역할을 담당한다. getBean() 메서드를 제

supreme-ys.tistory.com

이 전 포스팅에 대한 답에 대한 포스팅이다.

 

스프링은 xml이나 annotation을 통해 빈을 등록할 수 있다. 빈을 등록할 때 스프링은 어떤 구조로 되어있길래 종류에 상관없이 빈을 등록할 수 있는지가 질문이었다. 그에 대한 답은 BeanDefinition에서 찾을 수 있다. 

 

BeanDefinition은 추상화이다. 역할과 구현을 개념적으로 나눈 것인데, BeanDefinition은 Xml을 읽거나, 자바 코드를 읽든 BeanDefinition을 만들면 된다. 따라서, 스프링 컨테이너는 자바 코드인지, XML인지 몰라도 된다. 오직 BeanDefinition만 알면된다.

 

@Bean(어노테이션), <bean>(xml)당 각각 하나씩 메타 정보가 생성되며, BeanDefinition을 빈 설정 메타정보라고 한다.

스프링 컨테이너는 이런 메타정보를 기반으로 스프링 빈을 생성하게 된다. 


이 전 포스팅에서 AnnotationConfigApplicationContext는 AnnotatedBeanDefinitionReader를 사용해서 AppConfig.class를 읽고 BeanDefinition을 생성한다. 

이와 마찬가지로 xml또한, GenericXmlApplicationContext는 XmlBeanDefinitionReader를 사용해서 appConfig.xml설정 정보를 읽고 BeanDefinition을 생성한다.

 

즉, 새로운 형식의 설정 정보가 추가되면, ---BeanDefinitionReader를 만들어서 BeanDefinition을 생성하면 된다.


간단하게 테스트 코드를 통해 어떤 메타 정보들이 생성되는지 파악해보자!

public class BeanDefinitionTest {

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName("빈 설정 메타정보 확인")
    void findApplicationBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

            if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
                System.out.println("beanDefinitionName = " + beanDefinitionName +
                        " beanDefinition = " + beanDefinition);
            }
        }
    }
}
beanDefinitionName = appConfig beanDefinition = 중략
beanDefinitionName = memberService beanDefinition = 중략
beanDefinitionName = orderService beanDefinition = 중략
beanDefinitionName = memberRepository beanDefinition = 중략
beanDefinitionName = discountPolicy beanDefinition = Root bean: 중략
package practice.spring.core;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import practice.spring.core.discount.DiscountPolicy;
import practice.spring.core.discount.RateDiscountPolicy;
import practice.spring.core.member.MemberRepository;
import practice.spring.core.member.MemberService;
import practice.spring.core.member.MemberServiceImpl;
import practice.spring.core.member.MemoryMemberRepository;
import practice.spring.core.order.OrderService;
import practice.spring.core.order.OrderServiceImpl;

/**
 * @Configuration : 설정을 구성한다는 뜻의 어노테이션
 * @Bean : 스프링 컨테이너에 빈(bean)으로 등록한다.
 */
@Configuration
public class AppConfig {

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

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

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

    @Bean
    public DiscountPolicy discountPolicy() {
        // 만약에 정액할인정책이 아니라 정률로만 바꾸고 싶다면?
        // return new FixDiscountPolicy();
        // 이런식으로 "구성 영역"에서 바꿔만 주면 된다.
        return new RateDiscountPolicy();
    }
}

AppConfig에서 등록한 4가지 메서드와 1개의 AppConfig 설정 정보를 담은 클래스가 빈으로 등록된 것을 알 수 있다. 총 5가지!