본문 바로가기
강의 실습/스프링 핵심 원리 - 기본편

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

by jint 2026. 4. 12.

스프링이 다양한 설정 형식을 지원하는 것은 BeanDefinition 이라는 추상화 때문이다. 즉 역할과 구현을 개념적으로 나눈 것이다!
  -> XML 읽어서 BeanDefinition 생성
  -> 자바 코드 읽어서 BeanDefinition 생성

스프링 컨테이너는 XML인지 자바 코드인지 몰라도 오직 BeanDefinition 만 알면 된다. (추상화에만 의존 : 인터페이스 의존)

BeanDefinition : 빈 설정 메타정보. @Bean 또는 <bean> 당 각각 하나씩 메타 정보가 생성됨.

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

 

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


코드 레벨로 조금 더 깊이 있게 들어가면,

 

빈 메타정보 생성


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


1. BeanDefinition 살펴보기
1) BeanDefinition 정보
· BeanClassName : 생성할 빈의 클래스 명 (자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음 : ex. AppConfig.class)
· factoryBeanName : 팩토리 역할의 빈을 사용할 경우 이름
  예) appConfig
· factoryMethodName : 빈을 생성할 팩토리 메서드 지정
  예) memberService
· Scope : 싱글톤 (기본값)
· lazyInit : 스프링 컨테이너를 생성할 때 빈을 생성하는 것이 아니라, 실제 빈을 사용할 때까지 최대한 생성을 지연 처리 하는지 여부
· InitMethodName : 빈을 생성하고, 의존관계를 적용한 뒤에 호출되는 초기화 메서드 명
· DestroyMethodName : 빈의 생명주기가 끝나서 제거하기 직전에 호출되는 메서드 명
· Constructor arguments, Properties : 의존관계 주입에서 사용한다. (자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음 : ex. AppConfig.class)

- src/test/java/hello/core/beandefinition/BeanDefinitionTest.java

package hello.core.beandefinition;

import hello.core.AppConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class BeanDefinitionTest {

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    // GenericXmlApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");

    @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);
            }
        }
    }

}


- 콘솔 (AnnotationConfigApplicationContext)

beanDefinitionName = appConfig, beanDefinition = Generic bean: class=hello.core.AppConfig$$SpringCGLIB$$0; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null
beanDefinitionName = memberService, beanDefinition = Root bean: class=null; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=appConfig; factoryMethodName=memberService; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in hello.core.AppConfig
beanDefinitionName = orderService, beanDefinition = Root bean: class=null; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=appConfig; factoryMethodName=orderService; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in hello.core.AppConfig
beanDefinitionName = memberRepository, beanDefinition = Root bean: class=null; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=appConfig; factoryMethodName=memberRepository; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in hello.core.AppConfig
beanDefinitionName = discountPolicy, beanDefinition = Root bean: class=null; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=appConfig; factoryMethodName=discountPolicy; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in hello.core.AppConfig


- 콘솔 (GenericXmlApplicationContext)

beanDefinitionName = memberService, beanDefinition = Generic bean: class=hello.core.member.MemberServiceImpl; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null; defined in class path resource [appConfig.xml]
beanDefinitionName = orderService, beanDefinition = Generic bean: class=hello.core.order.OrderServiceImpl; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null; defined in class path resource [appConfig.xml]
beanDefinitionName = memberRepository, beanDefinition = Generic bean: class=hello.core.member.MemoryMemberRepository; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null; defined in class path resource [appConfig.xml]
beanDefinitionName = discountPolicy, beanDefinition = Generic bean: class=hello.core.discount.RateDiscountPolicy; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null; defined in class path resource [appConfig.xml]


* 빈 등록 방법 2가지
- XML은 직접 등록
- 자바 코드는 팩토리 빈의 팩토리 메서드를 통해 등록 (팩토리 메서드 : 외부에서 메서드를 호출하면 객체가 생성되는 방식)


2. 정리
1) BeanDefinition 을 직접 생성해서 스프링 컨테이너에 등록할 수도 있지만, 실무에서 BeanDefinition 을 직접 정의하거나 사용할 일은 거의 없다.
ApplicationContext 에는 getBeanDefinition() 메서드가 정의되어 있지 않다.
2) BeanDefinition 은 스프링이 다양한 형태의 설정 정보를 BeanDefinition 으로 추상화해서 사용한다는 것만 이해한다.
가끔 스프링 코드나 스프링 관련 오픈 소스 코드를 볼 때, BeanDefinition 이 등장하면 이런 메커니즘을 떠올리면 된다.

 

-> 스프링 컨테이너는 다양한 형태의 설정 정보를 BeanDefinition 으로 추상화해서 사용. 이 메타정보를 기반으로 스프링 빈 관리.


참고링크 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8?cid=325969

 

스프링 핵심 원리 - 기본편| 김영한 - 인프런 강의

현재 평점 5.0점 수강생 49,540명인 강의를 만나보세요. 스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 스프링 기본 기능, 스프

www.inflearn.com

댓글