๐Ÿ“– [Spring] ๐Ÿ’ป ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ - 4. ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์Šคํ”„๋ง ๋นˆ

๐Ÿ’ป [Spring] ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ - 4. ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์Šคํ”„๋ง ๋นˆ

์•ˆ๋…•ํ•˜์„ธ์š”. ๐Ÿ‘‹

์Šคํ”„๋ง์œผ๋กœ ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐœ๋ฐœํ–ˆ์—ˆ๋Š”๋ฐ 

๋ฌธ๋“ ์Šคํ”„๋ง ์ž์ฒด ํ•ต์‹ฌ ์›๋ฆฌ์— ๋Œ€ํ•œ ๋ณต์Šต์ด ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๊น€์˜ํ•œ๋‹˜์˜ ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ ๊ฐ•์˜๋ฅผ ๋“ค์œผ๋ฉฐ 

์Šคํ”„๋ง์„ ์™œ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š”์ง€์™€

์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ์— ๋Œ€ํ•ด ํ•™์Šตํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค. 

๋„ค๋ฒˆ์งธ ํฌ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋ถ€๋ฅผ ๋•Œ BeanFactory , ApplicationContext ๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ์ด์•ผ๊ธฐ ํ•˜์ง€๋งŒ BeanFactory ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๊ฑฐ์˜ ์—†์œผ๋ฏ€๋กœ ์ผ๋ฐ˜์ ์œผ๋กœ ApplicationContext ๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ผ ํ•œ๋‹ค.

  • ApplicationContext ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” XML์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ , ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ ์ž๋ฐ” ์„ค์ • ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ง์ „์— AppConfig ๋ฅผ ์‚ฌ์šฉํ–ˆ๋˜ ๋ฐฉ์‹์ด ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ ์ž๋ฐ” ์„ค์ • ํด๋ž˜์Šค๋กœ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋งŒ๋“  ๊ฒƒ ์ด๋‹ค.

  • ์ž๋ฐ” ์„ค์ • ํด๋ž˜์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ( ApplicationContext )๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

      new AnnotationConfigApplicationContext(AppConfig.class);
    

์ด ํด๋ž˜์Šค๋Š” ApplicationContext ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด์ด๋‹ค.

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ ๊ณผ์ •

1.์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ

create

new AnnotationConfigApplicationContext(AppConfig.class)
  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋Š” ๊ตฌ์„ฑ ์ •๋ณด๋ฅผ ์ง€์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.
  • ์—ฌ๊ธฐ์„œ๋Š” AppConfig.class ๋ฅผ ๊ตฌ์„ฑ ์ •๋ณด๋กœ ์ง€์ •ํ–ˆ๋‹ค.

bean

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜์–ด์˜จ ์„ค์ • ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•œ๋‹ค.
  • ๋นˆ ์ด๋ฆ„
    • ๋นˆ ์ด๋ฆ„์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๋นˆ ์ด๋ฆ„์„ ์ง์ ‘ ๋ถ€์—ฌํ•  ์ˆ˜ ๋„ ์žˆ๋‹ค.
    • ex) @Bean(name=โ€memberService2โ€) => memberService2 ๋กœ bean name์„ ๋ถ€์—ฌ

์ฃผ์˜: ๋นˆ ์ด๋ฆ„์€ ํ•ญ์ƒ ๋‹ค๋ฅธ ์ด๋ฆ„์„ ๋ถ€์—ฌํ•ด์•ผ ํ•œ๋‹ค. ๊ฐ™์€ ์ด๋ฆ„์„ ๋ถ€์—ฌํ•˜๋ฉด, ๋‹ค๋ฅธ ๋นˆ์ด ๋ฌด์‹œ๋˜๊ฑฐ๋‚˜, ๊ธฐ์กด ๋นˆ์„ ๋ฎ์–ด๋ฒ„๋ฆฌ๊ฑฐ๋‚˜ ์„ค์ •์— ๋”ฐ๋ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

ready

fin

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์„ค์ • ์ •๋ณด๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…(DI)ํ•œ๋‹ค.
  • ๋‹จ์ˆœํžˆ ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ ๊ฐ™์ง€๋งŒ, ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.
  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ๋“ฑ๋ก๋œ ์Šคํ”„๋ง ๋นˆ๋“ค์„ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•ด์ค€๋‹ค.

์Šคํ”„๋ง์€ ๋นˆ์„ ์ƒ์„ฑํ•˜๊ณ , ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ๋‹จ๊ณ„๊ฐ€ ๋‚˜๋ˆ„์–ด์ ธ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๋ ‡๊ฒŒ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ์Šคํ”„๋ง ๋นˆ ์„ ๋“ฑ๋กํ•˜๋ฉด ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…๋„ ํ•œ๋ฒˆ์— ์ฒ˜๋ฆฌ๋œ๋‹ค.

์ •๋ฆฌ

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์„ค์ •(๊ตฌ์„ฑ) ์ •๋ณด๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์Šคํ”„๋ง ๋นˆ๋„ ๋“ฑ๋กํ•˜๊ณ , ์˜์กด๊ด€๊ณ„๋„ ์„ค์ •ํ–ˆ๋‹ค. ์ด์ œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ด๋ณด์ž.

์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ ๋ชจ๋“  ๋นˆ ์กฐํšŒ

์˜ˆ์ œ ์ฝ”๋“œ

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

    @Test
    @DisplayName("๋ชจ๋“  ๋นˆ ์ถœ๋ ฅํ•˜๊ธฐ")
    void findAllBean(){
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = ac.getBean(beanDefinitionName);
            System.out.println("name = " + beanDefinitionName + " object = " + bean);
        }
    }

    @Test
    @DisplayName("์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นˆ ์ถœ๋ ฅํ•˜๊ธฐ")
    void findApplicationBean(){
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
            
            //Role ROLE_APPLICATION: ์ง์ ‘ ๋“ฑ๋กํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นˆ (์ฃผ๋กœ ์‚ฌ์šฉ - ์ž์‹ ์ด ๊ฐœ๋ฐœํ•˜๊ธฐ ์œ„ํ•ด ์ง์ ‘ ๋“ฑ๋กํ•œ ๋นˆ)
            //Role ROLE_INFRASTRUCTURE: ์Šคํ”„๋ง์ด ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ
            if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){
                Object bean = ac.getBean(beanDefinitionName);
                System.out.println("name = " + beanDefinitionName + " object = " + bean);
            }
        }
    }
}

๋ชจ๋“  ๋นˆ ์ถœ๋ ฅํ•˜๊ธฐ

  • ์‹คํ–‰ํ•˜๋ฉด ์Šคํ”„๋ง์— ๋“ฑ๋ก๋œ ๋ชจ๋“  ๋นˆ ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ac.getBeanDefinitionNames() : ์Šคํ”„๋ง์— ๋“ฑ๋ก๋œ ๋ชจ๋“  ๋นˆ ์ด๋ฆ„์„ ์กฐํšŒํ•œ๋‹ค.
    • ac.getBean() : ๋นˆ ์ด๋ฆ„์œผ๋กœ ๋นˆ ๊ฐ์ฒด(์ธ์Šคํ„ด์Šค)๋ฅผ ์กฐํšŒํ•œ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นˆ ์ถœ๋ ฅํ•˜๊ธฐ
    • ์Šคํ”„๋ง์ด ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ์€ ์ œ์™ธํ•˜๊ณ , ๋‚ด๊ฐ€ ๋“ฑ๋กํ•œ ๋นˆ๋งŒ ์ถœ๋ ฅํ•ด๋ณด์ž.
    • ์Šคํ”„๋ง์ด ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ์€ getRole() ๋กœ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ROLE_APPLICATION : ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์ •์˜ํ•œ ๋นˆ
      • ROLE_INFRASTRUCTURE : ์Šคํ”„๋ง์ด ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ

์Šคํ”„๋ง ๋นˆ ์กฐํšŒ - ๊ธฐ๋ณธ

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ์Šคํ”„๋ง ๋นˆ์„ ์ฐพ๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์กฐํšŒ ๋ฐฉ๋ฒ•

  • ac.getBean(๋นˆ์ด๋ฆ„, ํƒ€์ž…)
  • ac.getBean(ํƒ€์ž…)
  • ์กฐํšŒ ๋Œ€์ƒ ์Šคํ”„๋ง ๋นˆ์ด ์—†์œผ๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ
    • NoSuchBeanDefinitionException: No bean named โ€˜xxxxxโ€™ available

์˜ˆ์ œ ์ฝ”๋“œ

package com.mks.core.beanfind;

import com.mks.core.AppConfig;
import com.mks.core.member.MemberService;
import com.mks.core.member.MemberServiceImpl;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

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

    @Test
    @DisplayName("๋นˆ ์ด๋ฆ„์œผ๋กœ ์กฐํšŒ")
    void findBeanByName(){
        MemberService memberService = ac.getBean("memberService", MemberService.class);
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }

    @Test
    @DisplayName("๋นˆ ์—†์ด ํƒ€์ž…์œผ๋กœ๋งŒ ์กฐํšŒ")
    void findBeanByType(){
        MemberService memberService = ac.getBean(MemberService.class);
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }

    @Test
    @DisplayName("๊ตฌ์ฒด ํƒ€์ž…์œผ๋กœ ์กฐํšŒ")
    void findBeanByName2(){
        MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class);
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }

    @Test
    @DisplayName("๋นˆ ์ด๋ฆ„์œผ๋กœ ์กฐํšŒx")
    void findBeanByNameX(){
        assertThatThrownBy(() -> {
            ac.getBean("xxxxx", MemberService.class);
        }).isInstanceOf(NoSuchBeanDefinitionException.class);
    }
}

๊ตฌ์ฒด ํƒ€์ž…์œผ๋กœ ์กฐํšŒํ•˜๋ฉด ๋ณ€๊ฒฝ์‹œ ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.

์Šคํ”„๋ง ๋นˆ ์กฐํšŒ - ๋™์ผํ•œ ํƒ€์ž…์ด ๋‘˜ ์ด์ƒ

  • ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ ๊ฐ™์€ ํƒ€์ž…์˜ ์Šคํ”„๋ง ๋นˆ์ด ๋‘˜ ์ด์ƒ์ด๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๋•Œ๋Š” ๋นˆ ์ด๋ฆ„์„ ์ง€์ •ํ•˜์ž.
  • ac.getBeansOfType() ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ํƒ€์ž…์˜ ๋ชจ๋“  ๋นˆ์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค

์˜ˆ์ œ ์ฝ”๋“œ

package com.mks.core.beanfind;

import com.mks.core.member.MemberRepository;
import com.mks.core.member.MemoryMemberRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class ApplicationContextSameBeanFindTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);

    @Test
    @DisplayName("ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ ๊ฐ™์€ ํƒ€์ž…์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด, ์ค‘๋ณต ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.")
    void findBeanByTypeDuplicate(){
        assertThatThrownBy(()->{
            MemberRepository bean = ac.getBean(MemberRepository.class);
        }).isInstanceOf(NoUniqueBeanDefinitionException.class);
    }

    @Test
    @DisplayName("ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ ๊ฐ™์€ ํƒ€์ž…์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด, ๋นˆ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ๋œ๋‹ค.")
    void findBeanByName(){
        MemberRepository memberRepository = ac.getBean("memberRepository1",MemberRepository.class);
        assertThat(memberRepository).isInstanceOf(MemberRepository.class);
    }

    @Test
    @DisplayName("ํŠน์ • ํƒ€์ž…์„ ๋ชจ๋‘ ์กฐํšŒํ•˜๊ธฐ")
    void findBeanByType(){
        Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
        for (String key : beansOfType.keySet()) {
            System.out.println("key = " + key + "value = "+beansOfType.get(key));
        }
        System.out.println("beansOfType = " + beansOfType);
        assertThat(beansOfType.size()).isEqualTo(2);
    }

    @Configuration
    static class SameBeanConfig{
        @Bean
        public MemberRepository memberRepository1(){
            return new MemoryMemberRepository();
        }
        @Bean
        public MemberRepository memberRepository2(){
            return new MemoryMemberRepository();
        }
    }
}

์Šคํ”„๋ง ๋นˆ ์กฐํšŒ - ์ƒ์† ๊ด€๊ณ„

  • ๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ์กฐํšŒํ•˜๋ฉด, ์ž์‹ ํƒ€์ž…๋„ ํ•จ๊ป˜ ์กฐํšŒํ•œ๋‹ค.
  • ๊ทธ๋ž˜์„œ ๋ชจ๋“  ์ž๋ฐ” ๊ฐ์ฒด์˜ ์ตœ๊ณ  ๋ถ€๋ชจ์ธ Object ํƒ€์ž…์œผ๋กœ ์กฐํšŒํ•˜๋ฉด, ๋ชจ๋“  ์Šคํ”„๋ง ๋นˆ์„ ์กฐํšŒํ•œ๋‹ค.

inherit

์˜ˆ์ œ ์ฝ”๋“œ

public class ApplicationContextExtendsFindTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);

    @Test
    @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ, ์ž์‹์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด, ์ค‘๋ณต ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.")
    void findBeanByParentTypeDuplicate(){
        assertThatThrownBy(()->{
            DiscountPolicy bean = ac.getBean(DiscountPolicy.class);
        }).isInstanceOf(NoUniqueBeanDefinitionException.class);
    }

    @Test
    @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ, ์ž์‹์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด, bean ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ๋œ๋‹ค.")
    void findBeanByParentTypeBeanName(){
        DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy",DiscountPolicy.class);
       assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
    }

    @Test
    @DisplayName("ํŠน์ • ํ•˜์œ„ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ")
    void findBeanBySubType(){
        DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy",DiscountPolicy.class);
        assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
    }

    @Test
    @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ๋ชจ๋‘ ์กฐํšŒํ•˜๊ธฐ")
    void findAllBeanByParentType(){
        Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
        assertThat(beansOfType.size()).isEqualTo(2);
    }

    @Configuration
    static class TestConfig {
        @Bean
        public DiscountPolicy rateDiscountPolicy(){
            return new RateDiscountPolicy();
        }
        @Bean
        public DiscountPolicy fixDiscountPolicy(){
            return new FixDiscountPolicy();
        }
    }
}

BeanFactory์™€ ApplicationContext

bean-factory-and-application-context

BeanFactory
  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์ตœ์ƒ์œ„ ์ธํ„ฐํŽ˜์ด์Šค๋‹ค.
  • ์Šคํ”„๋ง ๋นˆ์„ ๊ด€๋ฆฌํ•˜๊ณ  ์กฐํšŒํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•œ๋‹ค.
  • getBean() ์„ ์ œ๊ณตํ•œ๋‹ค.
  • ์ง€๊ธˆ๊นŒ์ง€ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ–ˆ๋˜ ๋Œ€๋ถ€๋ถ„์˜ ๊ธฐ๋Šฅ์€ BeanFactory๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.
ApplicationContext
  • BeanFactory ๊ธฐ๋Šฅ์„ ๋ชจ๋‘ ์ƒ์†๋ฐ›์•„์„œ ์ œ๊ณตํ•œ๋‹ค.
  • ๋นˆ์„ ๊ด€๋ฆฌํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ธฐ๋Šฅ์„ BeanFactory๊ฐ€ ์ œ๊ณตํ•ด์ฃผ๋Š”๋ฐ, ๊ทธ๋Ÿฌ๋ฉด ๋‘˜์˜ ์ฐจ์ด๊ฐ€ ๋ญ˜๊นŒ?
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๋•Œ๋Š” ๋นˆ์€ ๊ด€๋ฆฌํ•˜๊ณ  ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์€ ๋ฌผ๋ก ์ด๊ณ , ์ˆ˜ ๋งŽ์€ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜๋‹ค.
  • ์ˆ˜ ๋งŽ์€ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜๋งŽ์€ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด ์žˆ๋Š” ApplicationContext๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

ApplicatonContext๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ถ€๊ฐ€๊ธฐ๋Šฅ

ApplicationContext

  • ๋ฉ”์‹œ์ง€์†Œ์Šค๋ฅผ ํ™œ์šฉํ•œ ๊ตญ์ œํ™” ๊ธฐ๋Šฅ
    • ์˜ˆ๋ฅผ ๋“ค์–ด์„œ ํ•œ๊ตญ์—์„œ ๋“ค์–ด์˜ค๋ฉด ํ•œ๊ตญ์–ด๋กœ, ์˜์–ด๊ถŒ์—์„œ ๋“ค์–ด์˜ค๋ฉด ์˜์–ด๋กœ ์ถœ๋ ฅ
  • ํ™˜๊ฒฝ๋ณ€์ˆ˜
    • ๋กœ์ปฌ, ๊ฐœ๋ฐœ, ์šด์˜๋“ฑ์„ ๊ตฌ๋ถ„ํ•ด์„œ ์ฒ˜๋ฆฌ
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ด๋ฒคํŠธ
    • ์ด๋ฒคํŠธ๋ฅผ ๋ฐœํ–‰ํ•˜๊ณ  ๊ตฌ๋…ํ•˜๋Š” ๋ชจ๋ธ์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ง€์›
  • ํŽธ๋ฆฌํ•œ ๋ฆฌ์†Œ์Šค ์กฐํšŒ
    • ํŒŒ์ผ, ํด๋ž˜์ŠคํŒจ์Šค, ์™ธ๋ถ€ ๋“ฑ์—์„œ ๋ฆฌ์†Œ์Šค๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์กฐํšŒ

์ •๋ฆฌ

  • ApplicationContext๋Š” BeanFactory์˜ ๊ธฐ๋Šฅ์„ ์ƒ์†๋ฐ›๋Š”๋‹ค.
  • ApplicationContext๋Š” ๋นˆ ๊ด€๋ฆฌ๊ธฐ๋Šฅ + ํŽธ๋ฆฌํ•œ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.
  • BeanFactory๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ผ์€ ๊ฑฐ์˜ ์—†๋‹ค. ๋ถ€๊ฐ€๊ธฐ๋Šฅ์ด ํฌํ•จ๋œ ApplicationContext๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • BeanFactory๋‚˜ ApplicationContext๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ผ ํ•œ๋‹ค.

๋‹ค์–‘ํ•œ ์„ค์ • ํ˜•์‹ ์ง€์› - ์ž๋ฐ” ์ฝ”๋“œ, XML

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ๋‹ค์–‘ํ•œ ํ˜•์‹์˜ ์„ค์ • ์ •๋ณด๋ฅผ ๋ฐ›์•„๋“œ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ ์œ ์—ฐํ•˜๊ฒŒ ์„ค๊ณ„๋˜์–ด ์žˆ๋‹ค.
  • ์ž๋ฐ” ์ฝ”๋“œ, XML, Groovy ๋“ฑ๋“ฑ

bean-facotry

์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ ์ž๋ฐ” ์ฝ”๋“œ ์„ค์ • ์‚ฌ์šฉ
  • ์ง€๊ธˆ๊นŒ์ง€ ํ–ˆ๋˜ ๊ฒƒ์ด๋‹ค.
  • new AnnotationConfigApplicationContext(AppConfig.class)
  • AnnotationConfigApplicationContext ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์ž๋ฐ” ์ฝ”๋“œ๋กœ๋œ ์„ค์ • ์ •๋ณด๋ฅผ ๋„˜๊ธฐ๋ฉด ๋œ๋‹ค.
XML ์„ค์ • ์‚ฌ์šฉ
  • ์ตœ๊ทผ์—๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋ฉด์„œ XML๊ธฐ๋ฐ˜์˜ ์„ค์ •์€ ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ์•„์ง ๋งŽ์€ ๋ ˆ๊ฑฐ์‹œ ํ”„๋กœ์  ํŠธ ๋“ค์ด XML๋กœ ๋˜์–ด ์žˆ๊ณ , ๋˜ XML์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํŒŒ์ผ ์—†์ด ๋นˆ ์„ค์ • ์ •๋ณด๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ๋„ ์žˆ์œผ๋ฏ€ ๋กœ ํ•œ๋ฒˆ์ฏค ๋ฐฐ์›Œ๋‘๋Š” ๊ฒƒ๋„ ๊ดœ์ฐฎ๋‹ค.

  • GenericXmlApplictionContext ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ xml ์„ค์ • ํŒŒ์ผ์„ ๋„˜๊ธฐ๋ฉด ๋œ๋‹ค.

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>

XmlAppConfig ์‚ฌ์šฉ ์ž๋ฐ” ์ฝ”๋“œ

public class XmlAppContext {

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

    }
}
  • xml ๊ธฐ๋ฐ˜์˜ appConfig.xml ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด์™€ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ๋œ AppConfig.java ์„ค์ • ์ •๋ณด๋ฅผ ๋น„๊ตํ•ด๋ณด ๋ฉด ๊ฑฐ์˜ ๋น„์Šทํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

  • xml ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ์ตœ๊ทผ์—๋Š” ์ด์ œ ์ž˜ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.

  • ๊ณผ๊ฑฐ์—๋Š” ๋งŽ์ด ์‚ฌ์šฉ๋˜๋˜ ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•œ๋ฒˆ ๋ณด๊ณ  ์•Œ์•„๋‘๋Š” ์ •๋„!

์Šคํ”„๋ง ๋นˆ ์„ค์ • ๋ฉ”ํƒ€ ์ •๋ณด - โ€ป BeanDefinition

  • ์Šคํ”„๋ง์€ ์–ด๋–ป๊ฒŒ ์ด๋Ÿฐ ๋‹ค์–‘ํ•œ ์„ค์ • ํ˜•์‹์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ์ผ๊นŒ? ๊ทธ ์ค‘์‹ฌ์—๋Š” BeanDefinition ์ด๋ผ๋Š” ์ถ”์ƒํ™” ๊ฐ€ ์žˆ๋‹ค.
  • ์‰ฝ๊ฒŒ ์ด์•ผ๊ธฐํ•ด์„œ ์—ญํ• ๊ณผ ๊ตฌํ˜„์„ ๊ฐœ๋…์ ์œผ๋กœ ๋‚˜๋ˆˆ ๊ฒƒ์ด๋‹ค!

    • XML์„ ์ฝ์–ด์„œ BeanDefinition์„ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค. (XML ๋ฐฉ์‹)

    • ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ์ฝ์–ด์„œ BeanDefinition์„ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค. (Java ์ฝ”๋“œ ์„ค์ • ๋ฐฉ์‹)

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์ž๋ฐ” ์ฝ”๋“œ์ธ์ง€, XML์ธ์ง€ ๋ชฐ๋ผ๋„ ๋œ๋‹ค. ์˜ค์ง BeanDefinition๋งŒ ์•Œ๋ฉด ๋œ๋‹ค.

  • BeanDefinition ์„ ๋นˆ ์„ค์ • ๋ฉ”ํƒ€์ •๋ณด๋ผ ํ•œ๋‹ค.

  • @Bean , ๋‹น ๊ฐ๊ฐ ํ•˜๋‚˜์”ฉ ๋ฉ”ํƒ€ ์ •๋ณด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์ด ๋ฉ”ํƒ€์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์„ ์ƒ์„ฑํ•œ๋‹ค

bean-definition

  • AnnotationConfigApplicationContext ๋Š” AnnotatedBeanDefinitionReader ๋ฅผ ์‚ฌ์šฉํ•ด์„œ

  • AppConfig.class ๋ฅผ ์ฝ๊ณ  BeanDefinition ์„ ์ƒ์„ฑํ•œ๋‹ค.

  • GenericXmlApplicationContext ๋Š” XmlBeanDefinitionReader ๋ฅผ ์‚ฌ์šฉํ•ด์„œ appConfig.xml ์„ค์ • ์ •๋ณด๋ฅผ ์ฝ๊ณ  BeanDefinition ์„ ์ƒ์„ฑํ•œ๋‹ค.

  • ์ƒˆ๋กœ์šด ํ˜•์‹์˜ ์„ค์ • ์ •๋ณด๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด, XxxBeanDefinitionReader๋ฅผ ๋งŒ๋“ค์–ด์„œ BeanDefinition ์„ ์ƒ์„ฑ ํ•˜๋ฉด ๋œ๋‹ค.

์ •๋ฆฌ

  • BeanDefinition์„ ์ง์ ‘ ์ƒ์„ฑํ•ด์„œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•  ์ˆ˜ ๋„ ์žˆ๋‹ค.

  • ํ•˜์ง€๋งŒ ์‹ค๋ฌด์—์„œ BeanDefinition์„ ์ง์ ‘ ์ •์˜ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•  ์ผ์€ ๊ฑฐ์˜ ์—†๋‹ค.!

  • โ€ป BeanDefinition์— ๋Œ€ํ•ด์„œ๋Š” ๋„ˆ๋ฌด ๊นŠ์ด์žˆ๊ฒŒ ์ดํ•ดํ•˜๊ธฐ ๋ณด๋‹ค๋Š”, ์Šคํ”„๋ง์ด ๋‹ค์–‘ํ•œ ํ˜•ํƒœ์˜ ์„ค์ • ์ •๋ณด๋ฅผ BeanDefinition์œผ๋กœ ์ถ”์ƒํ™”ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ์ •๋„๋งŒ ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค.

๋

์Šคํ”„๋ง์„ ๋” ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊น€์˜ํ•œ๋‹˜์˜ ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ ๊ฐ•์˜๋ฅผ ๋“ค์œผ๋ฉฐ ์ •๋ฆฌํ•œ
๋„ค๋ฒˆ์งธ ํฌ์ŠคํŠธ์˜€์Šต๋‹ˆ๋‹ค.
๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ™

์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ ํฌ์ŠคํŠธ

1. ๊ฐ์ฒด ์ง€ํ–ฅ ์„ค๊ณ„์™€ ์Šคํ”„๋ง
2. ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ ์ดํ•ด 1,2 3. IoC, DI, ๊ทธ๋ฆฌ๊ณ  ์ปจํ…Œ์ด๋„ˆ 4. ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์Šคํ”„๋ง ๋นˆ


Reference

๊น€์˜ํ•œ๋‹˜์˜ ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ

Written on June 2, 2021