인프런/스프링핵심원리(기본)

12)BeanFactory, ApplicationContext ,다양한 설정 형식 지원(자바코드, XML) , 스프링 빈 설정 메타정보(BeanDefinition)

backend dev 2022. 12. 27.

그림에서 알 수 있듯이 어플리케이션컨텍스트는 빈 팩토리를 상속받는다.

상속받은 인터페이스를 구현하는 AnnotationConfigApplicationContext(구현 클래스,구현체)

BeanFactory (빈 팩토리)

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

- 스프링빈을 관리하고 조회하는 역할 담당

- 이전 시간에 썼던 getBean()과 같이 사용했던 대부분의 기능은 빈팩토리에서 제공하는 기능이였다.

 

ApplicationContext

- 빈팩토리를 상속하는 인터페이스이므로 빈팩토리의 기능을 모두 상속받아서 제공한다.

- 빈팩토리와 차이는 뭘까? -> 빈을 관리하고 조회하는 기능(빈팩토리)은 물론이고 수많은 부가기능이 필요하기 때문에 

다른 인터페이스도 상속하고있다.

 

ApplicationContext가 빈팩토리 뿐만아니라 다른 인터페이스를 상속받는다.
상속받는 각 인터페이스에 대한 설명(왼쪽에서부터 순서대로)

 

 

 

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

이전에 AppConfig.class로 설정정보를 줘서 스프링컨테이너를 생성했듯이

appConfig.xml이라는 XML로도 생성이 가능하다. 

맨 오른쪽것처럼 임의의 설정해서 사용할 수 도 있다.

 

물론 자바코드를 많이 사용한다.

기존에 했던것들

 

 

XML 해보기

XmlAppContext.java

테스트파일을 생성해서 테스트해본다.

public class XmlAppContext {

    @Test
    void xmlAppContext() {
        ApplicationContext ac = new GenericXmlApplicationContext(
            "appConfig.xml"); //xml파일을 이용하여 스프링 컨테이너 생성

        MemberService memberService = ac.getBean("memberService", MemberService.class);
        assertThat(memberService).isInstanceOf(MemberService.class);
    }

}

중복 빈 테스트파일 코드짤때 ,임의의 Config클래스 생성해서 했던것처럼 appConfig.xml를 생성해준다.

 

하지만 XML파일은 resources밑에 파일로 생성해준다.

오른쪽마우스 -> new -> XML Configuration file -> spring config 로 생성

<?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">

</beans>

이 내용은 기본으로 들어가있다.

 

밑에 빈 추가해준다. ( 멤버서비스, 멤버리포지토리, 디스카운트폴리시 등등 AppConfig.java에서 해줬던것처럼)

 

<?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="com.example.demo.member.MemberServiceImpl">
    <constructor-arg name="memberRepository" ref="memberRepository"/>
  </bean>

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

  <bean id="discountPolicy" class="com.example.demo.discount.RateDiscountPolicy">
  </bean>


</beans>

 

위의 코드를 보면

AppConfig.java와 비슷하다는것을 알 수 있다. (형식만 xml인 느낌)

@Configuration
public class AppConfig { //프로젝트의 객체 생성,구성,주입 환경설정을 하는 중요 역할

    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(MemberRepository());
    }
    @Bean
    public MemberRepository MemberRepository() {
        return new MemoryMemberRepository();
    }
    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(MemberRepository(), DiscountPolicy());
    }
    @Bean
    public DiscountPolicy DiscountPolicy() {
        return new RateDiscountPolicy();
    }

}

테스트한 결과

xml 파일로도 스프링컨테이너에 빈이 잘 등록되는것을 확인할 수 있었다.

 

 

 

스프링 빈 설정 메타 정보(BeanDefinition)

XML을 읽어서 <bean>을 보고 그냥 메타정보를 만들기만 하면된다.

java 코드를 읽어서 @Bean을 보고 그냥 메타정보를 만들기만 하면된다.

 

스프링 컨테이너는 BeanDefinition만 의존한다

그 BeanDefinition이 자바로 된건지 xml로 된건지 뭐로된건지는 신경안쓴다 ( 역할에 의존한다. 구현에 의존하지않고)

 

Java,XML,임의

자바코드 사용해서 스프링컨테이너를 생성할때 사용했던 AnnotationConfigApplicationContext는 

Reader를 사용해서 AppConfig.class를 읽고 BeanDefinition(빈 메타정보)을 생성한다.

 

 

BeanDefinition(빈 메타정보) 살펴보기

BeanDefinitionTest.java

public class BeanDefinitionTest {

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName("빈 설정 메타정보 확인")
        //BeanDefinition 확인
    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);
            }
        }
    }
}

 

getBeanDefinition() 가 ApplicationContext에 없는 이유.

 

위의 테스트 출력 결과

beanDefinitionName = appConfig  beanDefinition = Generic bean: class [com.example.demo.AppConfig$$SpringCGLIB$$0]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=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; factoryBeanName=appConfig; factoryMethodName=memberService; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in com.example.demo.AppConfig
beanDefinitionName = MemberRepository  beanDefinition = Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appConfig; factoryMethodName=MemberRepository; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in com.example.demo.AppConfig
beanDefinitionName = orderService  beanDefinition = Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appConfig; factoryMethodName=orderService; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in com.example.demo.AppConfig
beanDefinitionName = DiscountPolicy  beanDefinition = Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appConfig; factoryMethodName=DiscountPolicy; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in com.example.demo.AppConfig

빈 메타정보이름 : 빈 이름

빈 메타정보 :   안에 엄청 많은 정보들이 담겨있다.

메타 정보 안에 각 정보들 설명

 

 

 

댓글