[Spring] 4-4. 다양한 설정 형식 지원

송광호·2023년 12월 20일

[Spring]

목록 보기
20/41
post-thumbnail

Spring 시리즈는 혼자 공부하며 기록으로 남기고, 만약 잘못 학습 한 지식이 있다면 공유하며 피드백을 받고자 작성합니다.
스프링에 대해 깊게 공부해보고자 인프런의 김영한 강사님께서 강의를 진행하시는 (스프링 핵심 원리 - 기본편) 강의를 수강하며 정리하는 글입니다.
혹여나 글을 읽으시며 잘못 설명된 부분이 있다면 지적 부탁드리겠습니다.


다양한 설정 형식 지원

  • 스프링 컨테이너는 다양한 형식의 설정 정보를 받아들일 수 있도록 유연하게 설계가 되어있다.
    • JAVA, XML, Groovy 등 외에도 직접 만들수도 있다.

예시 그림

애노테이션 기반 자바 코드 설정

  • 지금까지 계속 했던 것 - AppConfig.class, 이외에 테스트코드 작성할 때 @Configuration 애노테이션 사용했던 것들
  • new AnnotationConfigApplicationContext(AppConfig.class)
    • 이 클래스를 사용하면서 자바 코드로된 설정 정보를 넘기면 된다.

XML 설정

  • 최근에는 스프링 부트를 많이 사용하게 되면서 거의 사용하지 않는 방식이다.
  • 컴파일 없이 빈 설정 정보를 변경할 수 있는 장점도 있다.
  • GenericXmlApplicationContext를 사용하면서 xml 설정 정보를 넘기면 된다.

Xml 설정 자바 코드

import static org.assertj.core.api.Assertions.*;

public class XmlAppContext {

    @Test
    void xmlAppContext() {
        ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
        MemberService memberService = ac.getBean("memberService", MemberService.class);

        assertThat(memberService).isInstanceOf(MemberService.class);
    }
}
  • GenericXmlApplicationContext()에 xml 설정 정보를 넘기면된다.

appConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="memberService" class="hello.core.member.MemberServiceImpl" >
        <constructor-arg name="memberRepository" ref="memberRepository" />
    </bean>

    <bean id="memberRepository" class="hello.core.member.MemoryMemberRepository"/>

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

    <bean id="discountPolicy" class="hello.core.discount.RateDiscountPolicy"/>

</beans>
  • 이전에 작성했던 AppConfig자바코드를 그대로 xml로 변경한것이다.
  • 보면 바로 알 수 있을만큼 거의 유사하다. 나는 자바가 좀 더 편하다..

스프링 빈 설정 메타 정보

  • 스프링은 어떻게 이런 다양한 설정 형식 제공하는가? 라고 의구심을 가진다면 그 중심에는 BeanDefinition이라는 추상화가 존재한다.

BeanDefinition

  • 역할구현을 개념적으로 나눈 것
  • 스프링 컨테이너는 구현 되어있는게 자바코드인지 XML인지 모른다.
    • XML로 구현되었다면 XML을 읽어서 BeanDefinition을 만들면 된다.
    • JAVA로 구현되었다면 JAVA 코드를 읽어서 BeandDefinition을 만들면 된다.
  • BeanDefinition을 빈 설정 메타정보라고 한다.
    • @bean, <bean> 빈 하나당 각각 하나씩 메타정보가 생성된다.
    • 스프링 컨테이너는 이 메타정보를 기반으로 스프링 빈을 생성한다.

코드 레벨

  • AnnotationConfigApplicationContextAnnotatedBeanDefinitionReader를 사용하여 AppConfig.class 를 읽고 BeanDefinition을 생성한다.

    • 이게 무슨소리인가 싶은데 AnnotationConfigApplicationContext 내부 코드를 살펴보자
    public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    
        private final AnnotatedBeanDefinitionReader reader;
    }

    보면 설정 정보를 읽어들이는 AnnotatedBeanDefinitionReader가 존재한다. 이름 그대로 애노테이션 형식으로 작성된 코드를 읽어들여서 BeanDefinition을 만들어내는 역할을 한다.

  • Xml이나 직접만든 설정 정보도 같은 방식으로 동작한다.

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, getRole() 나왔는데 기억 안나면 앞 게시글 다시 와보도록 하자.

출력 결과

출력 정보

  • BeanClassName : 생성할 빈의 클래스 명(자바 설정처럼 팩토리 역할의 빈을 사용하면 없음)
  • factoryBeanName : 팩토리 역할의 빈을 사용할 경우 이름, ex) appConfig
  • factoryMethodName : 빈을 생성할 팩토리 메서드 지정, ex)memberService
  • Scope : 싱글톤(기본값)
  • 등등 엄청 여러 정보들이 나온다. 그 외 자세하게 알고싶다면 김영한 강사님의 강의를 참고해보도록 하자

정리

  • BeanDefinition을 직접 생성해서 스프링 컨테이너에 등록할 수도 있다.
    • 하지만 실무에서 BeanDefinition을 직접 정의하거나 사용할 일은 거의 존재하지 않는다.

팩토리 메서드?

  • AnnotationConfigApplicationContext는 팩토리 메서드를 통해서 등록하는 방법이다.
  • GoF 디자인 패턴때 배웠던 내용같은데 한번 알아봐야겠다.

0개의 댓글