공부/Spring

[Spring] 스프링 빈 설정 메타 정보 - BeanDefinition

sesam 2023. 11. 10. 21:20
728x90

 

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

스프링은 어떻게 이런 다양한 설정 형식을 지원하는 것일까?

스프링 컨테이너는 왜 어노테이션을 활용한 자바코드(@bean)인지 xml로 빈을 등록한 건지 상관이 없는 걸까?

그 중심에는 BeanDefinition 이라는 추상화가 있다.

 

 

쉽게 이야기해서 역할과 구현을 개념적으로 나눈 것이다!

  • XML을 읽어서 BeanDefinition을 만들면 된다.
  • 자바 코드를 읽어서 BeanDefinition을 만들면 된다.
  • 스프링 컨테이너는 자바 코드인지, XML인지 몰라도 된다.
  • 추상화(역할)인 BeanDefinition을 사용하기 때문에, 오직 BeanDefinition만 알면 된다.

 

BeanDefinition빈 설정 메타정보라 한다.

@Bean , 당 각각 하나씩 메타 정보가 생성된다.

스프링 컨테이너는 이 메타정보를 기반으로 스프링 빈을 생성한다

  • AnnotationConfigApplicationContext 는 AnnotatedBeanDefinitionReader 를 사용해서 AppConfig.class 를 읽고 BeanDefinition 을 생성한다.
  • GenericXmlApplicationContext 는 XmlBeanDefinitionReader 를 사용해서 appConfig.xml 설정 정보를 읽고 BeanDefinition 을 생성한다.
  • 새로운 형식의 설정 정보가 추가되면, XxxBeanDefinitionReader를 만들어서 BeanDefinition 을 생성하 면 된다.

 

코드예시

AppConfig가 어노테이션을 활용한 자바코드일 때

테스트코드로 진행

test/beanfind/BeanDefinitonTest.java

public class BeanDefinitionTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName("빈 설정 메타정보 확인")
    void findApplicationBean() {
        // ApplicationContext를 쓰면 getBeanDefinitionNames이 없기 때문에 AnnotationConfigApplicationContext를 써줘야 한다..
        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);
            }
        }
    }
}

결과 화면

 어노테이션활용한 자바코드로 실행했을 때는 bean에 대한  class 경로가 null인 것을 확인할 수 있다.

 어노테이션활용한 자바코드로 실행했을 때는

factoryBeanName=appConfig;

factoryMethodName=memberService 가 명시되어 있다.

 

appConfing.xml일 때

public class BeanDefinitionTest {
    GenericXmlApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");

    @Test
    @DisplayName("빈 설정 메타정보 확인")
    void findApplicationBean() {
        // ApplicationContext를 쓰면 getBeanDefinitionNames이 없기 때문에 AnnotationConfigApplicationContext를 써줘야 한다..
        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);
            }
        }
    }
}

beanDefinition = Generic bean: class [hello.core.member.MemberServiceImpl]

bean에 대한 class 경로가 구체적으로 명시되어 있다.

xml로 실행했을 때는

factoryBeanName=null; factoryMethodName=null 가 null인 것을 확인 할 수 있다.

defined는 AppConfig로 명시되어 있다.

 

 

➕ 참고 ➕

factoryBeanName에는 무슨 차이가 있을까? 

빈 등록 방법에는 크게 2가지가 있다.

1. bean을 직접 컨테이너에 올리는 방법(xml사용)

2. Factory Method를 통해서 올리는 방법(@Bean 자바코드 사용)

 

그렇기 때문에 위에서 appCofing,xml을 사용했을 때는

factoryBeanName=null;

factoryMethodName=null 가 null인 것이다.