본문 바로가기
Spring

스프링 핵심 원리 기본편 - 챕터 4

by mingutistory 2023. 3. 12.
728x90

Chapter 4. 스프링 컨테이너와 스프링 빈

스프링 컨테이너 생성

ApplicationContext(인터페이스)를 스프링 컨테이너라 한다.

XML 기반으로도 만들 수 있고, 에노테이션 기반의 자바 설정 클래스로도 만들 수 있다.

 

스프링 컨테이너 생성(AppConfig.class - 구성 정보) -> 스프링 컨테이너 (스프링 빈 저장소) -> 빈 이름, 빈 객체

빈 이름 빈 객체
memberService MemberServiceImpl@x01
orderService OrderServiceImpl@x02
memberRepository MemoryMembmerRepository@03

빈 이름은 항상 다른 이름을 부여 해야 한다. 기존 빈을 덮어버리거나 설정에 따라 오류가 발생한다.

애매한 건 실무에서 사용하지 말자.

 

스프링 빈을 생성 한 뒤 설정 정보(AppConfig)를 참고해서 의존 관계를 주입(DI)함.

 

스프링의 경우 1. 빈 생성 2. 의존관계를 주입한다. 단계가 나뉘어 있음. (실제 LifeCycle)

자바 코드로 스프링 빈을 등록하면 의존 관계 주입도 한번에 처리 된다. 

 

 

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

    @Test
    @DisplayName("애플리케이션 빈 출력하기")
    void findApplicationBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

            // ROLE_APPLICATION 직접 등록한 애플리케이션 빈
            // ROLE_INFRASTRUCTURE: 스프링 내부에서 사용하는 빈
            if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
                Object bean = ac.getBean(beanDefinitionName);
                System.out.println("name = " + beanDefinitionName + "object = " + bean);
            }
        }
    }

 

 

스프링 빈 조회 - 기본

실패한 경우에 대한 테스트 코드도 잘 작성하자.

 

스프링 빈 조회 - 상속 관계

중요

부모 타입으로 조회하면, 자식 타입도 함께 조회한다.

부모 타입으로 조회 시, 자식이 둘 이상 있을 때 NoUniqueBeanDefinitionException 발생. 이런 경우에는 빈 이름을 지정하여 조회하거나 특정 구체 타입으로 조회한다.

 

BeanFactory와 ApplicationContext

BeanFactory

스프링 컨테이너 최상위 인터페이스

스프링 빈 관리 및 조회 역할

거의 직접 사용하지 않음

 

ApplicationContext

빈을 관리하고 검색하는 기능은 BeanFactory에서 제공하지만 그걸 상속 받아 모두 제공하고 부가 기능을 추가한다.

스프링 컨테이너

// 실제 ApplicationContext 클래스
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
}

MessageSource: 국제화 - 한국에서 들어오면 한국어, 영어권의 경우 영어

환경변수: 로컬, 개발, 운영 등 다양한 프로젝트 환경에 대해서 구분해서 처리 할 수 있게함

 

 

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

다양한 형식의 설정 정보를 받아드릴 수 있게 유연하게 설계되어 있음

 

AnnotationConfigApplicationContext (AppConfig.class) - 애노테이션 기반

// ApplicationContext 상속 받아서 사용 하는 것 확인 가능
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
}

 

GenericXmlApplicationContext (AppConfig.xml) - XML 설정 기반

스프링 부트 사용하면서 XML 기반 설정을 잘 사용하지 않게 됨.

하지만 아직 우리 회사 같이 레거시 프로젝트들은 xml로 많이 되어 있으니 배워두는 것이 좋다.

 

AppConfig.class에서 

    <bean id="orderService" class="hello.demo.order.OrderServiceImpl">
        <constructor-arg name="memberRepository" ref="memberRepository"></constructor-arg>
        <constructor-arg name="discountPolicy" ref="discountPolicy"></constructor-arg>
    </bean>

 

XxxApplicationContext

다양하게 정의해서도 사용 할 수 있다. 

 

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

약간 교양 수업..

 

스프링이 어떻게 다양한 형식들로 설정 형식을 지원하는지는 BeanDefinition 추상화를 보면 알 수 있다.

 

스프링 컨테이너는 BeanDefinition(설정 메타 정보, (ex: @Bean, <bean>...)을 읽어서 스프링 빈을 생성한다.

실제 BeanDefinition은 인터페이스로 구현되어 있어서 스프링 컨테이너는 그냥 뭐로 구현되어있든 구현체(어노테이션 컨텍스트, Xml 컨텍스트...)에서 각각의 Bean에 대한 BeanDefinition만 맞춰주면 빈을 생성(BeanFactory) 할 수 있다

 

public class GenericXmlApplicationContext extends GenericApplicationContext {
	// XmlBeanDefinitionReader를 통해 appConfig.xml 문서를 읽고 BanDefinition 생성
	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
}

 

AppConfig.class에 설정한 Bean에 대한 BeanDefinition 정보 출력

일단 지금은 이런 정보들이 있고 메타 정보들이 있다 라고 알아두자.

 

beanDefinitionName = memberService 

beanDefinition = Root bean: class [null]; scope=(기본은 싱글톤); abstract=false; lazyInit=null(실제 사용하는 시점에서 빈 생성); autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appConfig; factoryMethodName=memberService; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in hello.demo.AppConfig

 

BeanDefinition을 직접 생성해서 스프링 컨테이너에 등록할 수 있지만 실무에서 사용 할 일 거의 없음

 

appConfig.xml 출력 방식.

beanDefinitionName = memberService

beanDefinition = Generic bean: class [hello.demo.member.MemberServiceImpl]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null; defined in class path resource [appConfig.xml]

 

차이점

xml의 경우에는 스프링에 빈이 직접적으로 등록되는 것이고 어노테이션(자바 설정 파일)의 경우에는 factoryMethod .. 어짜고로 간접적으로 우회에서 등록함.

그래서 xml 쪽에서는 class가 명확하게 보이지만 어노테이션 쪽에서는 보이지 않는다.

 

300x250

댓글