ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [๊ฐ•์˜] ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ 3
    SPRING/INFLEARN 2021. 5. 16. 20:40

    ์ด๋ฒˆ์ฃผ ์–‘ ๋งŽ๋‹ค... ํ™”์ดํŒ…

    inf.run/wr1v

     

    ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

    ์Šคํ”„๋ง ์ž…๋ฌธ์ž๊ฐ€ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋ฉด์„œ ์Šคํ”„๋ง์˜ ํ•ต์‹ฌ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ณ , ์Šคํ”„๋ง ๊ธฐ๋ณธ๊ธฐ๋ฅผ ํ™•์‹คํžˆ ๋‹ค์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ณ , ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ณด์„ธ์š”! ๐Ÿ“ฃ ํ™•์ธํ•ด์ฃผ

    www.inflearn.com

     

    ์ถœ์ฒ˜:  ๊น€์˜ํ•œ ๊ฐ•์‚ฌ๋‹˜ ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ-  ๊ธฐ๋ณธํŽธ

     

    4.์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์Šคํ”„๋ง ๋นˆ

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

    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

    ApplicationContext <- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ, ์ธํ„ฐํŽ˜์ด์Šค

     

    ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์ฃผ๋กœ ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ ์ž๋ฐ” ์„ค์ • ํฌ๋ž˜์Šค๋กœ ๋งŒ๋“ ๋‹ค (XML๋กœ ๋งŒ๋“ค๊ธฐ๋„, ์ž˜ ์•ˆ์”€)

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

    -> ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜์–ด์˜จ ์„ค์ • ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ๊ตฌ์„ฑ ์ •๋ณด๋กœ ์‚ฌ์šฉํ•˜์—ฌ
        ์• ๋…ธํ…Œ์ด์…˜ ๋ถ™์€ ๊ฒƒ๋“ค์„ ์ฐพ์•„๋‹ค๋‹ˆ๋ฉด์„œ ์Šคํ”„๋ง ๋นˆ ๋“ฑ๋ก

        * ๋นˆ ์ด๋ฆ„์€ ๋ชจ๋‘ ๋‹ฌ๋ผ์•ผํ•œ๋‹ค.

    -> ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์„ค์ • ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…

     

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

    ApplicationContextInfoTest.java๋กœ ์กฐํšŒํ•œ๋‹ค.

    ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์ง  ์ฝ”๋“œ์—์„œ ์“ฐ์ด๋Š” ๊ฒƒ ๋ฟ ์•„๋‹ˆ๋ผ ์Šคํ”„๋ง ๋‚ด๋ถ€์˜ ๋นˆ๊นŒ์ง€ ๋‹ค ๋‚˜์˜จ๋‹ค.

    ์•„๋ž˜ ๋‹ค์„ฏ๊ฐœ ์ˆœ์„œ๋Œ€๋กœ AppConfig, ๋“ฑ๋กํ•œ ๋นˆ๋“ค

     

    ๋”ฐ๋ผ์„œ ์•„๋ž˜์— ์šฐ๋ฆฌ๊ฐ€ ์ง  ์ฝ”๋“œ์—์„œ ์“ฐ์ด๋Š” ๊ฒƒ๋“ค๋งŒ ์ถœ๋ ฅํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค.

    ์ž˜ ๋‚˜์˜จ๋‹ค.

     

    ac.getBeanDefinitionNames() : ์Šคํ”„๋ง์— ๋“ฑ๋ก๋œ ๋ชจ๋“  ๋นˆ ์ด๋ฆ„ ์กฐํšŒ
    ac.getBean(๋นˆ ์ด๋ฆ„) : ๋นˆ ์ด๋ฆ„์œผ๋กœ ๋นˆ ๊ฐ์ฒด ์กฐํšŒ

     

    getRole() ->
    ROLE_APPLICATION : ์‚ฌ์šฉ์ž ์ •์˜ ๋นˆ
    ROLE_INFRASTRUCTURE : ์Šคํ”„๋ง์ด ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ

     

    soutv ๊ฐ’ System.out.println์œผ๋กœ ์ถœ๋ ฅ

    ctrl + D ๋ณต์ œ

     

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

    getBean์„ ์‚ฌ์šฉํ•˜๋Š” 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•

    1) ๋นˆ ์ด๋ฆ„์œผ๋กœ ์กฐํšŒ

    2) ํƒ€์ž…์œผ๋กœ๋งŒ ์กฐํšŒ

    3) ๊ตฌ์ฒด ํƒ€์ž…์œผ๋กœ ์กฐํšŒ

    //ApplicationContextBasicFindTest.java
    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("๋นˆ ์ด๋ฆ„์œผ๋กœ ์กฐํšŒํ–ˆ๋Š”๋ฐ ์—†๋Š” ์ด๋ฆ„")
        void findBeanByNameX(){
            /*MemberService memberService = ac.getBean("xxxx", MemberService.class);
            //No bean named 'xxxx' available ์˜ค๋ฅ˜ ๋œฌ๋‹ค.*/
            org.junit.jupiter.api.Assertions.assertThrows(NoSuchBeanDefinitionException.class,
                    () -> ac.getBean("xxxx", MemberService.class));
    
        }
    }
    

     

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

    AppConfig๋ฅผ  ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์„œ ์•„๊นŒ์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํ…Œ์ŠคํŠธ ํ•˜๋ฉด ํ•˜๋‚˜๋งŒ ์ฐพ์•„์ ธ์•ผ ํ•˜์ง€๋งŒ ๋‘๊ฐœ๊ฐ€ ์ฐพ์•„์กŒ๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋œฌ๋‹ค.

    //ApplicationContextSameBeanFindTest.java
    public class ApplicationContextSameBeanFindTest {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
    
        @Test
        @DisplayName("ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ ๊ฐ™์€ ํƒ€์ž…์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด, ์ค‘๋ณต ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.")
        void findBeanByTypeDuplicate(){
            //MemberRepository bean = ac.getBean(MemberRepository.class);
            Assertions.assertThrows(NoUniqueBeanDefinitionException.class,
                    () -> ac.getBean(MemberRepository.class));
        }
    
        @Test
        @DisplayName("ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ ๊ฐ™์€ ํƒ€์ž…์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด, ๋นˆ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ๋œ๋‹ค.")
        void findBeanName(){
            MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);
            assertThat(memberRepository).isInstanceOf(MemberRepository.class);
        }
    
        @Test
        @DisplayName("ํŠน์ • ํƒ€์ž…์„ ๋ชจ๋‘ ์กฐํšŒํ•˜๊ธฐ")
        void findAllBeanByType(){
            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);
        }
    
    
        //AppConfig ์ค‘๋ณต ์žˆ๋Š” ๊ฑธ๋กœ ์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ
        @Configuration
        static class SameBeanConfig{
    
            @Bean
            public MemberRepository memberRepository(){
                return new MemoryMemberRepository();
            }
    
            @Bean
            public MemberRepository memberRepository2(){
                return new MemoryMemberRepository();
            }
    
        }
    }
    

    ๊ฐ™์€ ํƒ€์ž…์ด ๋‘˜ ์ด์ƒ์ผ ๊ฒฝ์šฐ, ๋ฐ›์„ ๋นˆ ์ด๋ฆ„์„ ์ง์ ‘ ์ •ํ•˜๊ณ  ํƒ€์ž…์œผ๋กœ ์กฐํšŒํ•˜๋ฉด Mapํด๋ž˜์Šค๊ฐ€ ๋‚˜์˜จ๋‹ค.

    ์œ ์ผํ•˜๊ฒŒ ์ถœ๋ ฅ์ด ์žˆ์—ˆ๋˜ ๋ฉ”์†Œ๋“œ ์ถœ๋ ฅ ์ž˜๋จ

     

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

    ๋Œ€์›์น™ : ๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ์กฐํšŒํ•˜๋ฉด ์ž์‹ ํƒ€์ž…์€ ํ•จ๊ป˜ ์กฐํšŒ๋œ๋‹ค.

    //ApplicationContextExtendsFindTest.java
    public class ApplicationContextExtendsFindTest {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
        
        @Test
        @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ ์ž์‹์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด ์ค‘๋ณต ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค")
        void findBeanByParentTypeDuplicate(){
            assertThrows(NoUniqueBeanDefinitionException.class,
                    () -> ac.getBean(DiscountPolicy.class));
        }
    
        @Test
        @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ ์ž์‹์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด ๋นˆ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ๋œ๋‹ค")
        void findBeanByParentTypeBeanName(){
            DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
            assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
        }
    
        @Test
        @DisplayName("ํŠน์ • ํ•˜์œ„ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ")
        void findBeanBySubType(){
            RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
            assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
            //๊ตฌ์ฒด์ ์ธ rate์–ด์ฉŒ๊ตฌ๋Š” ํ•˜๋‚˜๋ฐ–์— ์—†๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž…์œผ๋กœ ํ•œ๋ฒˆ์— ์ž˜ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.
        }
    
        @Test
        @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ๋ชจ๋‘ ์กฐํšŒ")
        void findAllBeanByParentType(){
            Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
            assertThat(beansOfType.size()).isEqualTo(2);
            for(String key : beansOfType.keySet()){
                System.out.println("key = " + key + " value = " + beansOfType.get(key));
            }
        }
    
        @Test
        @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ๋ชจ๋‘ ์กฐํšŒ - Object Type")
        void findAllBeanByObjectType(){
            Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
            for(String key : beansOfType.keySet()){
                System.out.println("key = " + key + " value = " + beansOfType.get(key));
            }
        }
    
    
        @Configuration
        static class TestConfig{
            
            @Bean
            public DiscountPolicy rateDiscountPolicy(){
                return new RateDiscountPolicy();
            }
    
            @Bean
            public DiscountPolicy fixDiscountPolicy(){
                return new FicDiscountPolicy();
            }
        }
    }
    

    ๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ๋ชจ๋‘ ์กฐํšŒ ์•„์ฃผ ์ž˜ ๋จ
    ์ฝ”๋“œ์— ์žˆ๋Š” ๊ฒƒ ๋ฟ ์•„๋‹ˆ๋ผ ์Šคํ”„๋ง ๋‚ด๋ถ€์˜ ๋นˆ๊นŒ์ง€ ์šฐ๋ฅด๋ฅด~ ๋ชจ๋‘ Object์˜ ํ•˜์œ„ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

     

    - BeanFactory์™€ ApplicationContext

    BeanFactory
    ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์ตœ์ƒ์œ„ ์ธํ„ฐํŽ˜์ด์Šค
    ์Šคํ”„๋ง ๋นˆ ๊ด€๋ฆฌ, ์กฐํšŒ

    ↓์ƒ์†

    ApplicationContext
    BeanFactory ๊ธฐ๋Šฅ์„ ๋ชจ๋‘ ์ƒ์†๋ฐ›์•„์„œ ์ œ๊ณต

    ํ•˜์ง€๋งŒ BeanFactory ๋ฟ ์•„๋‹ˆ๋ผ ๋งŽ์€ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ๋“ค๋„ ์ƒ์†๋ฐ›๋Š”๋‹ค.

    ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์—๋Š” BeanFactory ์™ธ์—๋„ ์ˆ˜ ๋งŽ์€ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

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

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

    ์ž๋ฐ” ์ฝ”๋“œ ๋ฟ ์ด๋‹ˆ๋ผ XML ๋“ฑ ๋‹ค์–‘ํ•œ ํ˜•์‹์„ ์ง€์›ํ•œ๋‹ค.

    ApplicationContext์„

    1) AnnotationConfigApplicationContext์— ์ž๋ฐ” ์ฝ”๋“œ ๋„˜๊ธฐ๊ธฐ

    2) GenericXmlApplication์— 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.java ๋ž‘ ์™„์ „ ๋˜‘๊ฐ™์€ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

    ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");๋กœ๋งŒ ๋ฐ”๊ฟ”์„œ ๋˜‘๊ฐ™์ด ํ…Œ์ŠคํŠธํ•˜๋ฉด ์ž˜ ๋œ๋‹ค!

     

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

    ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์ž๋ฐ” ์ฝ”๋“œ์ธ์ง€, XML์ธ์ง€ ๋ชฐ๋ผ๋„ ๋œ๋‹ค.
    ์ด๋ ‡๊ฒŒ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์ง€์›ํ•˜๋Š” ์ด์œ ๋Š” ๋ชจ๋‘ BeanDefinition์ด๋ผ๋Š” ์ถ”์ƒํ™”๋กœ ์ธ์‹ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    BeanDefinition์„ ์„ค์ • ๋ฉ”ํƒ€ ์ •๋ณด๋ผ๊ณ  ํ•œ๋‹ค. @Bean๋‹น ํ•˜๋‚˜์˜ ๋ฉ”ํƒ€์ •๋ณด๋ฅผ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค.

    app config ํŒŒ์ผ์˜ ํ˜•์‹์— ๋งž๋Š” reader๋กœ ์„ค์ • ์ •๋ณด๋ฅผ ์ฝ๊ณ  ๋นˆ ๋ฉ”ํƒ€์ •๋ณด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    //BeanDefinitionTest.java
    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("beanDefinition = " + beanDefinition
                    + " beanDefinition = " + beanDefinition);
                }
            }
        }
    }
    

    ๋นˆ์„ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ง์ ‘๋“ฑ๋ก, Factory ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ.

    ์ €์žฅ๋˜๋Š” ํ˜•์‹์ด ์กฐ๊ธˆ ๋‹ค๋ฆ„

     

    5.์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ

    - ์›น ์• ํ•„๋ฆฌ์ผ€์ด์…˜๊ณผ ์‹ฑ๊ธ€ํ†ค

    ์Šคํ”„๋ง์€ ์ฃผ๋กœ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์‚ฌ์šฉ๋˜๋Š”๋ฐ ์›น์€ ๋ณดํ†ต ์—ฌ๋Ÿฌ ๊ณ ๊ฐ์ด ๋™์‹œ์— ์š”์ฒญํ•œ๋‹ค.

    ->์š”์ฒญ์ด ์˜ฌ ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“œ๋Š”๊ฐ€?

    yes ๋‘๊ฐœ ์ƒ์„ฑ๋จ

    ํ•˜์ง€๋งŒ ๊ฐ™์€ ๊ฐ์ฒด ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ๋งค๋ฒˆ ์ƒ๊ธฐ๋Š” ๊ฒƒ์€ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„!

    -> ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๊ณต์œ ํ•˜๋„๋ก : ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด

     

    - ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด

    ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋”ฑ 1๊ฐœ๋งŒ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด

    -> ๋‘๊ฐœ์ด์ƒ ์ƒ์„ฑ๋˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰๋Š”๋‹ค.

    //SingletonService.java
    public class SingletonService {
    
        //static์— ๊ฐ์ฒด ์˜ฌ๋ ค๋‘๊ธฐ
        private static final SingletonService instance = new SingletonService();
    
        //์กฐํšŒ
        public static SingletonService getInstance(){
            return instance;
        }
    
        //์ƒ์„ฑ์ž๋ฅผ private๋กœ ๋ง‰๋Š”๋‹ค ***
        private SingletonService(){ }
    
        public void logic(){
            System.out.println("์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด ๋กœ์ง ํ˜ธ์ถœ");
        }
    }

     

    ์ด์ œ ๋‘ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค!

    ํ•˜์ง€๋งŒ ๋‹จ์   :

    ์ฝ”๋“œ๊ฐ€ ๋งŽ์ด ๋“ค์–ด๊ฐ(Singleton Service)

    ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กด DIP, OCP์œ„๋ฐ˜

    ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์›€

    private๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง

    ๋“ฑ๋“ฑ ๊ฐ–๊ฐ€์ง€ ๋‹จ์ ๋“ค์ด ์žˆ๋‹ค.

     

    ๊ทธ๋Ÿฌ๋‚˜!! ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹ฑ๊ธ€ํ†ค์„ ์•Œ์•„์„œ ๊ตฌํ˜„ํ•ด์ค€๋‹ค!!

     

    - ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ

    Bean์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด, ์Šคํ”„๋ง์€ ํ•œ ํด๋ž˜์Šค ๋‹น ๊ฐ์ฒด ํ•˜๋‚˜์”ฉ๋งŒ ๋“ฑ๋กํ•ด์„œ ๊ด€๋ฆฌํ•œ๋‹ค.

    ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์‹ฑ๊ธ€ํ†ค์€ ์œ„์˜ ๋‹จ์ ๋“ค์„ ๋ชจ๋‘ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

    ๊ฐ™์€ ๊ฐ์ฒด์ž„์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

    ์Šคํ”„๋ง์€ ์‹ฑ๊ธ€ํ†ค ๋ฟ ์•„๋‹ˆ๋ผ ๋งค๋ฒˆ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•œ๋‹ค.

     

    - ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์˜ ์ฃผ์˜์ 

    ์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•˜๋‚˜์˜ ๊ฐ™์€ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

    -> ๋ฌด์ƒํƒœ ์„ค๊ณ„
    ํŠน์ • ํด๋ผ์ด์–ธํŠธ์— ์˜์กด์ ์ด๋ฉด ์•ˆ๋จ
    ํŠน์ • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ’ ์ˆ˜์ •์ด ๋ถˆ๊ฐ€๋Šฅํ•ด์•ผํ•จ, ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•˜๋ฉด ์ข‹์Œ

    ํ•„๋“œ ๋Œ€์‹  ์ง€์—ญ๋ฒˆ์ˆ˜, ํŒŒ๋ผ๋ฏธํ„ฐ, ThreadLocal๋“ฑ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•จ

     

    ๋ฌธ์ œ ์ƒํ™ฉ

    //StatefulService.java
    public class StatefulService {
    
        private int price;
    
        public void order(String name, int price){
            System.out.println("name = " + name + " price = " + price);
            this.price = price;
        }
    
        public int getPrice(){
            return price;
        }
    }
    //StatefulServiceTest.java
    public class StatefulServiceTest {
    
        @Test
        void statefulServiceSingleton(){
            ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
            StatefulService statefulService1 = ac.getBean(StatefulService.class);
            StatefulService statefulService2 = ac.getBean(StatefulService.class);
    
            //ThreadA: A๊ฐ€ 10000์› ์ฃผ๋ฌธ
            statefulService1.order("userA", 10000);
            //ThreadB: B๊ฐ€ 20000์› ์ฃผ๋ฌธ
            statefulService2.order("userB", 20000);
    
            //ThreadA: A ์ฃผ๋ฌธ ๊ธˆ์•ก ์กฐํšŒ
            int price = statefulService1.getPrice();
            System.out.println("price = " + price);
    
            //์ค‘๊ฐ„์— ์‚ฌ์šฉ์ž B๊ฐ€ ๋ฐ”๊พธ์–ด๋ฒ„๋ ธ์œผ๋ฏ€๋กœ price๋Š” 20000์›์ด ๋‚˜์˜ค๊ฒŒ ๋œ๋‹ค.
            //๊ฐ™์€ ๊ฐ์ฒด์ด๋ฏ€๋กœ ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ
            Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
    
        }
    
        static class TestConfig{
    
            @Bean
            public StatefulService statefulService(){
                return new StatefulService();
            }
        }
    }

    ์•ˆ๋ผ!! userA๋Š” ์ด๋งŒ์›์งœ๋ฆฌ๋ฅผ ์ฃผ๋ฌธํ•˜์ง€ ์•Š์•˜์–ด!!

    ํ•ด๊ฒฐ

    //StatefulService.java
    public class StatefulService {
        public int order(String name, int price){
            System.out.println("name = " + name + " price = " + price);
            return price;
        }
    }
    //StatefulServiceTest.java
    public class StatefulServiceTest {
    
        @Test
        void statefulServiceSingleton(){
            ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
            StatefulService statefulService1 = ac.getBean(StatefulService.class);
            StatefulService statefulService2 = ac.getBean(StatefulService.class);
    
            //ThreadA: A๊ฐ€ 10000์› ์ฃผ๋ฌธ
            int userAPrice = statefulService1.order("userA", 10000);
    
            //ThreadB: B๊ฐ€ 20000์› ์ฃผ๋ฌธ
            int userBPrice = statefulService2.order("userB", 20000);
    
            //ThreadA: A ์ฃผ๋ฌธ ๊ธˆ์•ก ์กฐํšŒ
            System.out.println("price = " + userAPrice);
    
            //๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
            Assertions.assertThat(userAPrice).isEqualTo(10000);
    
        }
    
        static class TestConfig{
    
            @Bean
            public StatefulService statefulService(){
                return new StatefulService();
            }
        }
    }
    

    ํŽธ-์•ˆ

    - @Configuration๊ณผ ์‹ฑ๊ธ€ํ†ค

    memberService ๋นˆ -> memberRepository() ํ˜ธ์ถœ -> MemoryMemberRepository() ํ˜ธ์ถœ
    orderService ๋นˆ -> memberRepository() ํ˜ธ์ถœ -> MemoryMemberRepository() ํ˜ธ์ถœ

    => ์‹ฑ๊ธ€ํ†ค์ด ๊นจ์ง€๋Š” ๊ฒŒ ์•„๋‹Œ๊ฐ€?!

    ํ•˜์ง€๋งŒ ์Šคํ”„๋ง์€ ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•ด์ค€๋‹ค.

    //MemberServiceImpl.java
    public class MemberServiceImpl implements MemberService{
    	/*์ƒ๋žต*/
        public MemberRepository getMemberRepository(){
            return memberRepository;
        }
    }
    //OrderServiceImpl.java
    public class OrderServiceImpl implements OrderService{
        /*์ƒ๋žต*/
        public MemberRepository getMemberRepository(){
            return memberRepository;
        }
    }
    //ConfigurationSingletonTest.java
    public class ConfigurationSingletonTest {
    
        @Test
        void configurationTest(){
            ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    
            //memberService ํ˜ธ์ถœ memberRepository
            MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
            //orderService ํ˜ธ์ถœ memberRepository
            OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
            //์ฒ˜์Œ์— ๋นˆ์— ๋“ฑ๋ก๋œ memberRepository
            MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);
    
            MemberRepository memberRepository1 = memberService.getMemberRepository();
            MemberRepository memberRepository2 = orderService.getMemberRepository();
    
            System.out.println("memberService -> memberRepository = " + memberRepository1);
            System.out.println("orderService -> memberRepository = " + memberRepository2);
            System.out.println("memberRepository = " + memberRepository);
    
            assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
            assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
        }
    }
    

    ์„ธ๊ฐœ ๋ชจ๋‘ ๊ฐ™๋‹ค...!

     

    AppConfig์˜ DP์„ ์ œ์™ธํ•œ ๊ฐ Bean์— ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์ถœ๋ ฅ๋˜๋Š” call+soutm๋ฌธ์žฅ์„ ๋„ฃ์–ด๋†“์•˜๋‹ค.

    ๊ทธ๋ฆฌ๊ณ  ์ถœ๋ ฅํ•˜๋‹ˆ ์˜ˆ์ƒ(๋“ฑ๋ก MS->MR, ๋“ฑ๋ก MR, ๋“ฑ๋ก OS->MR)๊ณผ ๋‹ค๋ฅด๊ฒŒ ๋‚˜์˜จ๋‹ค!

    ๊ฐ ํ•œ ๋ฒˆ ์”ฉ ์„ธ ๋ฒˆ๋งŒ ๋‚˜์˜ค๊ณ  ๋งŒ๋‹ค!

     

    - @Configuration๊ณผ ๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘์˜ ๋งˆ๋ฒ•

    ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์Šคํ”„๋ง ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค์ด ๋˜๋„๋ก ๋ณด์žฅํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•˜๊ธฐ๋Š” ์–ด๋ ต๋‹ค.

    Appconfig๊ฐ€ ์•„๋‹Œ ๋’ค์— ์ด์ƒํ•œ๊ฒŒ ๋ถ™์€ ํด๋ž˜์Šค๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

    ์ด๋Ÿฐ ์ž„์˜์˜ ๋‹ค๋ฅธ ํด๋ž˜์Šค๊ฐ€ ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•ด์ค€๋‹ค.(CGLIB) <- ์ด๋Š” ์ž์‹ ํƒ€์ž…์ด๋‹ค.

    ์–˜๊ฐ€ ์Šคํ”„๋ง ๋นˆ์ด ์ด๋ฏธ ์žˆ์œผ๋ฉด ์Šคํ”„๋ง ๋นˆ ๋ฐ˜ํ™˜, ์—†์œผ๋ฉด ๋“ฑ๋กํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

    ๋˜ํ•œ ๋’ค์— ์ด์ƒํ•œ ์ด๋ฆ„์ด ๋ถ™์€ ํด๋ž˜์Šค์—ฌ๋„, ์›๋ž˜ ํด๋ž˜์Šค ์ด๋ฆ„์œผ๋กœ ์กฐํšŒ ๊ฐ€๋Šฅํ•จ

    ์ด๋Š” @Configuration ๋•๋ถ„์ด๋‹ค.

     

    @Configuration์„ ์ ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์‹ฑ๊ธ€ํ†ค์ด ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค!

    ์ˆœ์ˆ˜ํ•œ AppConfig์— ์ ‘๊ทผํ•˜์—ฌ @Bean๋“ค์€ ์ธ์‹ํ•ด์„œ ๋“ฑ๋กํ•จ

    ์•„๊นŒ ์˜ˆ์ƒํ–ˆ๋˜ ๋“ฑ๋ก MS->MR, ๋“ฑ๋ก MR, ๋“ฑ๋ก OS->MR, ์ฆ‰, MemberRepositiory๊ฐ€ ์„ธ๋ฒˆ ์ถœ๋ ฅ๋œ๋‹ค.

    -> ์‹ฑ๊ธ€ํ†ค์ด ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค!, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ๊ด€๋ จ์ด ์—†์–ด์ง

    ์ „๋ถ€ ์‹คํ–‰์‹œ์ผœ๋ณด๋ฉด ์„ธ๋ฒˆ ๋งŒ๋“ค์–ด์ง€๋Š” MemberRepositiory์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฐ๊ฐ ๋‹ค ๋‹ค๋ฅธ ๊ฒƒ ๋˜ํ•œ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

    @Autowired์“ฐ๊ธฐ๋„ ํ•˜๊ณ  ์–ด์ฉŒ๊ธด ํ•˜์ง€๋งŒ ๊ทธ๋ž˜๋„

    ๊ฒฐ๋ก  : ์žˆ์–ด์•ผ ํ•จ

     

    6.์ปดํฌ๋„ŒํŠธ ์Šค์บ”

    - ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž… ์‹œ์ž‘ํ•˜๊ธฐ

    @Bean์œผ๋กœ ์ผ์ผํžˆ ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ์€ ์Šคํ”„๋ง ๋นˆ์ด ๋งŽ์•„์ง€๋ฉด ํž˜๋“ค์–ด์ง

       ->Component scan, Autowired

    //AutoAppConfig.java
    @Configuration
    @ComponentScan(
            excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
            //์˜ˆ์ œ ์œ ์ง€ ์œ„ํ•ด ์ œ์™ธํ•  ๊ฒƒ๋“ค ์„ค์ •, Appconfig ๋ž‘ ๋ถ€๋”ชํž๊นŒ๋ด ์ผ๋‹จ ์„ค์ •
    )
    public class AutoAppConfig { }

    ์ด๋Š” @Component๊ฐ€ ๋ถ™์€ ํด๋ž˜์Šค๋ฅผ ์Šค์บ”ํ•ด์„œ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค.

    //AutoAppConfigTest.java
    public class AutoAppConfigTest {
    
        @Test
        void basicScan(){
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
    
            MemberService memberService = ac.getBean(MemberService.class);
            assertThat(memberService).isInstanceOf(MemberService.class);
        }
    }

    MemoryMemberRepository @Component ์ถ”๊ฐ€
    RateDiscountPolicy @Component ์ถ”๊ฐ€
    MemberServiceImpl @Component, ์ƒ์„ฑ์ž์— @Autowired ์ถ”๊ฐ€(์˜์กด ๊ด€๊ณ„ ์ฃผ์ž…)

    OrderServiceImpl @Component, ์ƒ์„ฑ์ž์— @Autowired ์ถ”๊ฐ€

    ๊ทธ๋ฆฌ๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณธ๋‹ค.

    //AutoAppConfigTest.java
    public class AutoAppConfigTest {
    
        @Test
        void basicScan(){
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
    
            MemberService memberService = ac.getBean(MemberService.class);
            assertThat(memberService).isInstanceOf(MemberService.class);
        }
    }

    ์ž˜ ๋Œ์•„๊ฐ€๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

    ๋นˆ์— ์˜ฌ๋ผ๊ฐ€๋Š” ์ด๋ฆ„์„ ๋ฐ”๊พธ๊ณ  ์‹ถ์œผ๋ฉด @Component(๋ฐ”๊พธ๊ณ  ์‹ถ์€ ์ด๋ฆ„)ํ•˜๋ฉด ๋œ๋‹ค. (๊ธฐ๋ณธ์€ ๋งจ์•ž๋งŒ ์†Œ๋ฌธ์ž์ธ ํด๋ž˜์Šค ์ด๋ฆ„)

    @ComponentScan์€ @Component ๊ฐ€ ๋ถ™์€ ๋ชจ๋“  ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค.

     

    @Autowired๋Š”์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ž๋™์œผ๋กœ ํ•ด๋‹น ์Šคํ”„๋ง ๋นˆ์„ ์ฐพ์•„์„œ ์ฃผ์ž…

    ex) OrderServiceImpl์˜ ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ memberRepository์™€ discountPolicy๊ฐ™์€ ์• ๋“ค์€ ์ด๋ฏธ ์žˆ๋Š” ๊ฒƒ์ด๋‹ˆ๊นŒ

    ํ•ด๋‹น ์Šคํ”„๋ง ๋นˆ์„ ์ฐพ์•„์„œ ์ฃผ์ž…. getBean์žฌ์งˆ

     

    - ํƒ์ƒ‰ ์œ„์น˜์™€ ๊ธฐ๋ณธ ์Šค์บ” ๋Œ€์ƒ

    @ComponentScan(
        basePackages = "ํƒ์ƒ‰ํ•  ํŒจํ‚ค์ง€์˜ ํƒ์ƒ‰ ์‹œ์ž‘ ์œ„์น˜ (Default : @ComponentScan ์ด ๋ถ™์€ ์„ค์ • ์ •๋ณด ํด๋ž˜์Šค์˜ ํŒจํ‚ค์ง€)",

        basePackageClasses = ์ง€์ •ํ•œ ํด๋ž˜์Šค์˜ ํŒจํ‚ค์ง€๋ฅผ ํƒ์ƒ‰ ์‹œ์ž‘ ์œ„์น˜๋กœ ์ง€์ •ํ•œ๋‹ค.
    }

    Springboot์—์„œ๋Š” @SpringBootApplication์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š”๋ฐ, ๊ทธ ์•„๋ž˜์—๋Š” ComponentScan์ด ์žˆ์Œ

    -> ์“ธ ํ•„์š” ์—†์Œ

     

    @Component : ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์—์„œ ์‚ฌ์šฉ
    @Controlller : ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์‚ฌ์šฉ
    @Service : ์Šคํ”„๋ง ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ์‚ฌ์šฉ (๋ณ„ ๊ธฐ๋Šฅ์€ ์—†์Œ, ๋ณด๊ธฐ ์ข‹์Œ)
    @Repository : ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์—์„œ ์‚ฌ์šฉ, ๋ฐ์ดํ„ฐ ๊ณ„์ธต์˜ ์˜ˆ์™ธ๋ฅผ ์Šคํ”„๋ง ์˜ˆ์™ธ๋กœ ๋ณ€ํ™˜
    @Configuration : ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด์—์„œ ์‚ฌ์šฉ, ์Šคํ”„๋ง ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค์„ ์œ ์ง€ํ•˜๋„๋ก ์ถ”๊ฐ€ ์ฒ˜๋ฆฌ

    -> ์ด ๊ฒƒ๋“ค ์•„๋ž˜์— ์ „๋ถ€ @Component์žˆ์Œ

     

    ์ž๋ฐ”์—๋Š” ์—๋…ธํ…Œ์ด์…˜ ์ƒ์† ๊ธฐ๋Šฅ์ด ์—†์œผ๋ฏ€๋กœ ์ด๊ฑธ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์Šคํ”„๋ง์ด ์ง€์›ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

     

    - ํ•„ํ„ฐ

    includeFilters : ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ ์ถ”๊ฐ€ ์ง€์ •
    excludeFilters : ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ์ œ์™ธํ•  ๋Œ€์ƒ

     

    ์Šค์บ” ๋Œ€์ƒ/ ์ œ์™ธ ์• ๋…ธํ…Œ์ด์…˜ 

    //MyIncludeComponent.java
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MyIncludeComponent { }
    
    //MyExcludeComponent.java
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MyExcludeComponent { }

    ์Šค์บ” ๋Œ€์ƒ ํด๋ž˜์Šค(BeanA)์—๋Š” @MyIncludeComponent๋ฅผ,

    ์Šค์บ” ์ œ์™ธ ํด๋ž˜์Šค(BeanB)์—๋Š” @MyExcludeComponent๋ฅผ ๋ถ™์—ฌ์ค๋‹ˆ๋‹ค.

     

    ์„ค์ • ์ •๋ณด์™€ ์Šค์บ” ๋Œ€์ƒ/์ œ์™ธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

    //ComponentFilerAppConfigTest.java
    public class ComponentFilerAppConfigTest {
        @Test
        void filterScan(){
            ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
            BeanA beanA = ac.getBean("beanA", BeanA.class);
            assertThat(beanA).isNotNull();
    
            assertThrows(
                    NoSuchBeanDefinitionException.class,
                    ()->ac.getBean("beanB", BeanB.class)
            );
    
        }
        @Configuration
        @ComponentScan(
            includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
            excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
        )
    
        static class ComponentFilterAppConfig { }
    }

    ์ œ์™ธ๋œ B๋Š” getBean์ด ์•ˆ๋˜๋ฏ€๋กœ assertTrows์— ๋„ฃ๋Š”๋‹ค.

    A๋Š” ํฌํ•จ๋˜์—ˆ๊ธฐ์— Null์ด ์•„๋‹ˆ๋ฏ€๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋‚˜์ง€ ์•Š๋Š”๋‹ค.

     

    - ์ค‘๋ณต ๋“ฑ๋ก๊ณผ ์ถฉ๋Œ

    FilterType. ANNOTATION: ๊ธฐ๋ณธ๊ฐ’, ์• ๋…ธํ…Œ์ด์…˜์„ ์ธ์‹ํ•ด์„œ ๋™์ž‘ํ•œ๋‹ค.(์ƒ๋žตํ•ด๋„ ๋จ)
                     ASSIGNABLE_TYPE: ์ง€์ •ํ•œ ํƒ€์ž…๊ณผ ์ž์‹ ํƒ€์ž…์„ ์ธ์‹ํ•ด์„œ ๋™์ž‘ํ•œ๋‹ค.
                     ASPECTJ: AspectJ ํŒจํ„ด ์‚ฌ์šฉ
                     REGEX: ์ •๊ทœ ํ‘œํ˜„์‹
                     CUSTOM: TypeFilter ์ด๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ์ฒ˜๋ฆฌ

     

    ์ค‘๋ณต๋“ฑ๋ก

    ์ž๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก - ์•Œ์•„์„œ ์˜ค๋ฅ˜๋‚จ
    ex) @Component("service") ๋‹ฌ๋ฆฐ ํด๋ž˜์Šค๊ฐ€ ๋‘ ๊ฐœ์ž„

    ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก - ์ˆ˜๋™์ด ์ž๋™์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•œ๋‹ค.

    ex) @Component๋‹ฌ๋ฆฐ ํด๋ž˜์Šค๊ณผ @Bean("์•ž ํด๋ž˜์Šค ์ด๋ฆ„") - ํ›„์ž๊ฐ€ ์ „์ž ์˜ค๋ฒ„๋ผ์ด๋“œ

    => ํ”ผํ•˜๋Š” ๊ฒŒ ์ข‹๋‹ค, ์• ๋งคํ•œ ์ƒํ™ฉ์„ ๊ตณ์ด ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์žˆ๋‚˜?

    ์˜€๋Š”๋ฐ, ์ตœ๊ทผ ์Šคํ”„๋ง๋ถ€ํŠธ์—์„œ๋Š” ์ˆ˜๋™& ์ž๋™์ด ์ถฉ๋Œํ•˜๋ฉด ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋„๋ก ๋ณ€๊ฒฝํ•จ

    - ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜๋Š” ์žˆ์Œ ํ•˜์ง€๋งŒ ์–ด์จŒ๋“  ์ด๋ฆ„ ๊ฒน์น˜๋Š”๊ฑด ๋ณ„๋กœ์ž„

     

     

Designed by Tistory.