๐ŸŒฑ ์Šคํ”„๋ง ์›๋ฆฌ (๊ธฐ๋ณธ)

yeopยท2023๋…„ 5์›” 29์ผ

โœ”๏ธ ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ ์ดํ•ด2 - ๊ฐ์ฒด ์ง€ํ–ฅ ์›๋ฆฌ ์ ์šฉ

๋‹คํ˜•์„ฑ์„ ๊ณ ๋ คํ•ด์„œ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ฐ์ฒด๋ฅผ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ ๊ฐ์ฒด๋ฅผ ๊ฐˆ์•„๋ผ์šฐ๋Š” ๊ณผ์ •์—์„œ DIP์™€ OCP๊ฐ€ ์ง€์ผœ์ง€์ง€์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๊ณผ์ •์„ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์ดํ•ดํ•˜๋Š” ์ฑ•ํ„ฐ

โ†’ ๊ฐœ๋ฐฉ ํ์‡„ ์›์น™์ธ OCP(ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ์–ด์•ผ ํ•˜์ง€๋งŒ ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.)์™€ ์˜์กด ์—ญ์ „ ์›์น™์ธ DIP(๊ฐ์ฒด๋Š” ๊ณ ์ฐจ์›์˜ ๋ชจ๋“ˆ์—๋งŒ ์˜์กดํ•  ๋ฟ ์ €์ฐจ์›์˜ ๋ชจ๋“ˆ์— ๋Œ€ํ•ด์„œ ์˜์กดํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค)๋ฅผ ์ง€ํ‚ค๊ธฐ ์œ„ํ•ด์„œ AppConfig๋ฅผ ์‚ฌ์šฉํ•ด ์˜์กด ๊ด€๊ณ„ ์ฃผ์ž…์„ ํ•ด์ค€๋‹ค.

  • AppConfig ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „์ฒด ๋™์ž‘ ๋ฐฉ์‹์„ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์—ฐ๊ฒฐํ•˜๋Š” ์ฑ…์ž„์„ ๊ฐ€์ง€๋Š” ๋ณ„๋„์˜ ์„ค์ • ํด๋ž˜์Šค AppConfig์—์„œ ๊ฐ ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉฐ ์ด๋ฅผ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ฃผ์ž…์‹œ์ผœ์ค€๋‹ค(์ƒ์„ฑ์ž ์ฃผ์ž…) ์ด์— ๋”ฐ๋ผ ๊ตฌํ˜„ ํด๋ž˜์Šค๋“ค์€ ๊ตฌํ˜„์ฒด์— ์˜์กดํ•˜์ง€ ์•Š์œผ๋ฉฐ ์–ด๋–ค ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ• ์ง€๋Š” ์˜ค์ง ์™ธ๋ถ€์—์„œ ๊ฒฐ์ •๋œ๋‹ค.

์ข‹์€ ๊ฐ์ฒด ์ง€ํ–ฅ ์„ค๊ณ„์˜ 5๊ฐ€์ง€ ์›์น™ ์ ์šฉ SOLID

  • SRP ๋‹จ์ผ ์ฑ…์ž„ ์›์น™ - ํ•œ ํด๋ž˜์Šค๋Š” ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค.
    • ๊ตฌํ˜„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์—ฐ๊ฒฐํ•˜๋Š” ์ฑ…์ž„์€ AppConfig๊ฐ€ ๋‹ด๋‹น
    • ํด๋ผ์ด์–ธํŠธ ๊ฐ์ฒด๋Š” ์‹คํ–‰ํ•˜๋Š” ์ฑ…์ž„๋งŒ ๋‹ด๋‹น
  • DIP ์˜์กด๊ด€๊ณ„ ์—ญ์ „ ์›์น™ - ์ถ”์ƒํ™”์— ์˜์กดํ•ด์•ผ์ง€, ๊ตฌ์ฒดํ™”์— ์˜์กดํ•˜๋ฉด ์•ˆ๋œ๋‹ค.
    • AppConfig๊ฐ€ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ ๋Œ€์‹  ์ƒ์„ฑํ•ด์„œ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์— ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž… ( ์ƒ์„ฑ์ž ์ฃผ์ž… )
  • OCP ๊ฐœ๋ฐฉ ํ์‡„ ์›์น™ - ํ™•์žฅ์—๋Š” ์—ด๋ ค ์žˆ์œผ๋‚˜ ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    • ๋‹คํ˜•์„ฑ์„ ์‚ฌ์šฉํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ๊ฐ€ DIP๋ฅผ ์ง€ํ‚ด
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉ์˜์—ญ๊ณผ ๊ตฌ์„ฑ์˜์—ญ์œผ๋กœ ๋‚˜๋ˆ”
    • ์†Œํ”„ํŠธ์›จ์–ด ์š”์†Œ๋ฅผ ์ƒˆ๋กญ๊ฒŒ ํ™•์žฅํ•ด๋„ ์‚ฌ์šฉ ์˜์—ญ์˜ ๋ณ€๊ฒฝ์€ ๋‹ซํ˜€ ์žˆ๋‹ค.

IoC, DI, ์ปจํ…Œ์ด๋„ˆ

  • IoC (Inversion of Control) ์ œ์–ด์˜ ์—ญ์ „
    • ๊ธฐ์กด์˜ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์—์„œ ๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์ฃผ์ž…์„ ๊ด€๋ฆฌํ•˜๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ด์—ˆ๋‹ค. ํ•˜์ง€๋งŒ DIP์™€ OCP๊ฐ€ ์ง€์ผœ์ง€์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด ์ œ์–ด์˜ ํ๋ฆ„์„ AppConfig์—๊ฒŒ ์ „์ž„ํ•ด ์ด DI์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์—ฐ๊ฒฐ, ์ฆ‰ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „์ฒด ๊ตฌ์„ฑ์„ ๊ด€๋ฆฌํ•œ๋‹ค.
    • ์ด๋ ‡๋“ฏ ์ œ์–ด์˜ ํ๋ฆ„์„ ์ง์ ‘ ์ œ์–ดํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์™ธ๋ถ€์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์ œ์–ด์˜ ์—ญ์ „์ด๋ผ๊ณ  ํ•œ๋‹ค.
  • DI (Dependency Injection)
    • ์ •์ ์ธ ํด๋ž˜์Šค ์˜์กด ๊ด€๊ณ„์™€ ๋™์ ์ธ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ์˜์กด๊ด€๊ณ„
      • ์ •์ ์ธ ํด๋ž˜์Šค ์˜์กด๊ด€๊ณ„๋Š” ํ•ด๋‹น ํด๋ž˜์Šค์˜ Import ๋‚ด์—ญ๋“ค์„ ๋ณด๋ฉด ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ๋™์ ์ธ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ์˜์กด๊ด€๊ณ„๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ์ (๋Ÿฐํƒ€์ž„)์— ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ, ์ฐธ์กฐ๊ฐ€ ์—ฐ๊ฒฐ๋œ ์˜์กด๊ด€๊ณ„์ด๋‹ค
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ์ (๋Ÿฐํƒ€์ž„)์— ์™ธ๋ถ€์—์„œ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์˜ ์‹ค์ œ ์˜์กด๊ด€๊ณ„๊ฐ€ ์—ฐ๊ฒฐ๋˜๋Š” ๊ฒƒ์„ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด๋ผ๊ณ  ํ•œ๋‹ค.
    • ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ์ •์ ์ธ ํด๋ž˜์Šค ์˜์กด๊ด€๊ณ„๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์‰ฝ๊ฒŒ ๋™์ ์ธ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ์˜์กด๊ด€๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

โœ”๏ธ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ์Šคํ”„๋ง ๋นˆ

์Šคํ”„๋ง ์ ์šฉ

  1. AppConfig ํด๋ž˜์Šค์— @Configuration Annotation์„ ๋ถ™์ด๊ณ  ๊ฐ ๋ฉ”์„œ๋“œ์— @Bean Annotation์„ ๋ถ™์ธ๋‹ค.
  2. ์ด์ „์—๋Š” ํ•„์š”ํ•œ ๊ฐ์ฒด๋ฅผ ๋ถ€๋ฅผ ๋•Œ AppConfig๋ฅผ ์„ ์–ธํ•ด ์ง์ ‘ ๋ถˆ๋Ÿฌ์™”์ง€๋งŒ ์ด์ œ๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ด์šฉํ•ด์„œ ํ•„์š”ํ•œ ์Šคํ”„๋ง ๋นˆ(๊ฐ์ฒด)๋ฅผ ์ฐพ์•„์•ผ ํ•œ๋‹ค.
//AppConfig appConfig = new AppConfig();
//MemberService memberService = appConfig.memberService();

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
  • ApplicationContext๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ผ๊ณ  ํ•œ๋‹ค.
  • AnnotationConfigApplicationContext๋Š” ApplicationContext ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด์ด๋‹ค.

์Šคํ”„๋ง ๋นˆ ์กฐํšŒ

  • ์˜ˆ์ œ์ฝ”๋“œ
    package hello.core.beanfind;
    
    import hello.core.discount.DiscountPolicy;
    import hello.core.discount.FixDiscountPolicy;
    import hello.core.discount.RateDiscountPolicy;
    import org.junit.jupiter.api.Assertions;
    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;
    
    public class ApplicationContextExtendsFindTest {
    
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
    
        @Test
        @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ, ์ž์‹์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด, ์ค‘๋ณต ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.")
        void findBeanByParentTypeDuplicate(){
            Assertions.assertThrows(NoUniqueBeanDefinitionException.class,
                    () -> ac.getBean(DiscountPolicy.class));
        }
    
        @Test
        @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ์‹œ, ์ž์‹์ด ๋‘˜ ์ด์ƒ ์žˆ์œผ๋ฉด, ๋นˆ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ๋œ๋‹ค.")
        void findByParentTypeBeanName() {
            DiscountPolicy bean = ac.getBean("RateDiscountPolicy",DiscountPolicy.class);
            org.assertj.core.api.Assertions.assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
        }
    
        @Test
        @DisplayName("ํŠน์ • ํ•˜์œ„ ํƒ€์ž…์œผ๋กœ ์กฐํšŒ")
        void findBeanBySubType(){
            RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
            org.assertj.core.api.Assertions.assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
        }
    
        @Test
        @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ๋ชจ๋‘ ์กฐํšŒํ•˜๊ธฐ")
        void findBeanByParentType() {
            Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
            org.assertj.core.api.Assertions.assertThat(beansOfType.size()).isEqualTo(2);
            for (String key : beansOfType.keySet()) {
                System.out.println("key = " + key + " value = " + beansOfType.get(key));
            }
        }
    
        @Test
        @DisplayName("๋ถ€๋ชจ ํƒ€์ž…์œผ๋กœ ๋ชจ๋‘ ์กฐํšŒํ•˜๊ธฐ - Object")
        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 FixDiscountPolicy();
            }
        }
    }

โ€ป static ์„ ๋ถ™์ด์ง€ ์•Š์€ inner class๋Š” outer class์— ์ข…์†๋œ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ outer class์˜ ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•œ ํ›„ inner class๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ static์„ ๋ถ™์ผ ๊ฒฝ์šฐ inner class์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋…๋ฆฝ์ ์ธ ๊ฐ์ฒด๋กœ ์„ ์–ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. โ†’ Static inner class๋Š” ํ•ด๋‹น outer class ๋‚ด์—์„œ ์„ ์–ธํ•˜์—ฌ ์ด์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ

BeanFactory์™€ ApplicationContext

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

BeanDefinition

  • ์Šคํ”„๋ง์€ ๋‹ค์–‘ํ•œ ํ˜•ํƒœ์˜ ์„ค์ • ์ •๋ณด๋ฅผ BeanDefinition์œผ๋กœ ์ถ”์ƒํ™”ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

โœ”๏ธ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด

  • ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ 1๊ฐœ๋งŒ ์ƒ์„ฑ๋˜๋„๋ก ๋ณด์žฅํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด
  • ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์œ ์ €์˜ ์š”์ฒญ์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๋ฉด ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ์ด ๋–จ์–ด์ง€๊ฒŒ ๋œ๋‹ค.

์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ๋งŒ๋“ค๊ธฐ

package hello.core.singleton;
public class SingletonService {
 //1. static ์˜์—ญ์— ๊ฐ์ฒด๋ฅผ ๋”ฑ 1๊ฐœ๋งŒ ์ƒ์„ฑํ•ด๋‘”๋‹ค.
 private static final SingletonService instance = new SingletonService();
 //2. public์œผ๋กœ ์—ด์–ด์„œ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋ฉด ์ด static ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์กฐํšŒํ•˜๋„๋ก
ํ—ˆ์šฉํ•œ๋‹ค.
 public static SingletonService getInstance() {
 return instance;
 }
 //3. ์ƒ์„ฑ์ž๋ฅผ private์œผ๋กœ ์„ ์–ธํ•ด์„œ ์™ธ๋ถ€์—์„œ new ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ์ฒด ์ƒ์„ฑ์„ ๋ชปํ•˜๊ฒŒ ๋ง‰๋Š”๋‹ค.
 private SingletonService() {
 }
 public void logic() {
 System.out.println("์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด ๋กœ์ง ํ˜ธ์ถœ");
 }
  • ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€์ด๋‹ค. ์—ฌ๊ธฐ์„œ ์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•์€ ๊ฐ์ฒด๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด๋‘๋Š” ๊ฐ€์žฅ ์•ˆ์ „ํ•˜๊ณ  ๋‹จ์ˆœํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ์ ๋“ค์ด ์žˆ๋‹ค.
    • ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” ์ฝ”๋“œ ์ž์ฒด๊ฐ€ ๋งŽ์ด ๋“ค์–ด๊ฐ„๋‹ค.
    • ์˜์กด๊ด€๊ณ„์ƒ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กดํ•œ๋‹ค. DIP๋ฅผ ์œ„๋ฐ˜ํ•œ๋‹ค.
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กดํ•ด์„œ OCP ์›์น™์„ ์œ„๋ฐ˜ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค.
    • ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
    • ๋‚ด๋ถ€ ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์ดˆ๊ธฐํ™” ํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
    • private ์ƒ์„ฑ์ž๋กœ ์ž์‹ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์–ด๋ ต๋‹ค.
    • ๊ฒฐ๋ก ์ ์œผ๋กœ ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.
    • ์•ˆํ‹ฐํŒจํ„ด์œผ๋กœ ๋ถˆ๋ฆฌ๊ธฐ๋„ ํ•œ๋‹ค

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ (โ†’ ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ)

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ (ApplicationContext or AnnotationConfigApplicationContext)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ํ•„์š”์—†์ด ์ž๋™์œผ๋กœ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌ๋œ๋‹ค.
  • ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์œ„ํ•œ ์ง€์ €๋ถ„ํ•œ ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
  • DIP, OCP, ํ…Œ์ŠคํŠธ, private ์ƒ์„ฑ์ž๋กœ ๋ถ€ํ„ฐ ์ž์œ ๋กญ๊ฒŒ ์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

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

  • ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์€ ์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€(Stateful)ํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜๋ฉด ์•ˆ๋œ๋‹ค.
  • ๋ฌด์ƒํƒœ๋กœ ์„ค๊ณ„ํ•ด์•ผํ•œ๋‹ค!!
    • ํŠน์ • ํด๋ผ์ด์–ธํŠธ์— ์˜์กด์ ์ธ ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค.
    • ํŠน์ • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค!
    • ๊ฐ€๊ธ‰์  ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค.
    • ํ•„๋“œ ๋Œ€์‹ ์— ์ž๋ฐ”์—์„œ ๊ณต์œ ๋˜์ง€ ์•Š๋Š”, ์ง€์—ญ๋ณ€์ˆ˜, ํŒŒ๋ผ๋ฏธํ„ฐ, ThreadLocal ๋“ฑ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๊ณต์œ ํ•„๋“œ๋ฅผ ์กฐ์‹ฌํ•˜๊ณ  ํ•ญ์ƒ ๋ฌด์ƒํƒœ๋กœ ์„ค๊ณ„ํ•˜์ž!

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

  • @Configuration ๋ฅผ ๋ถ™์ด๋ฉด ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ CGLIB์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‚ด๊ฐ€ ๋งŒ๋“  AppConfig๋ฅผ ์ƒ์†๋ฐ›์€ ์ž„์˜์˜ ์ž์‹ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค.
  • ์ด ์ž„์˜์˜ ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•ด์ค€๋‹ค.

โœ”๏ธ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”

์ปดํฌ๋„ŒํŠธ ์Šค์บ”, ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž…

  • ์ง€๊ธˆ๊นŒ์ง€๋Š” ์ž๋ฐ”์ฝ”๋“œ์— Bean Annotation ๋˜๋Š” XMLํŒŒ์ผ์˜ ์„ ์‚ฌ์šฉํ•ด ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•ด์ฃผ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ์Šคํ”„๋ง ๋นˆ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„์ง์— ๋”ฐ๋ผ ์ผ์ผ์ด ๋“ฑ๋กํ•˜๊ธฐ์—๋Š” ํšจ์œจ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค. โ†’ ๊ทธ๋ž˜์„œ ์Šคํ”„๋ง์€ ์„ค์ •์ •๋ณด ์—†์ด๋„ ์ž๋™์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•ด์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์ด๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ๋˜ํ•œ ์˜์กด๊ด€๊ณ„ ๋˜ํ•œ ์ž๋™์œผ๋กœ ์ฃผ์ž…ํ•ด์ฃผ๋Š” @Autowired ๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.
  1. ์„ค์ • ์ •๋ณด์— @ComponentScan์„ ๋ถ™์—ฌ์ค€๋‹ค.
  2. ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ  ์‹ถ์€ ํด๋ž˜์Šค์— @Component ๋ฅผ ๋ถ™์—ฌ์ค€๋‹ค
  3. ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ์œ„ํ•ด ํ•ด๋‹น ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž์— @Autowired ๋ฅผ ๋ถ™์—ฌ์ค€๋‹ค.

โ€ป @Configuration ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์—ด์–ด๋ณด๋ฉด @Component Annotation์ด ๋ถ™์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— @Configuration ๋˜ํ•œ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์˜ ๋Œ€์ƒ์ด ๋œ๋‹ค. ์ด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

@ComponentScan(
        excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {
}
  • @ComponentScan

    • @Component๊ฐ€ ๋ถ™์€ ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋Š”๋ฐ ์ด๋•Œ ์Šคํ”„๋ง ๋นˆ์˜ ์ด๋ฆ„์€ ํด๋ž˜์Šค๋ช…์„ ์‚ฌ์šฉํ•˜๋˜ ๋งจ ์•ž๊ธ€์ž๋งŒ ์†Œ๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    • ๋นˆ ์ด๋ฆ„ ์ง์ ‘ ์ง€์ •: @Component("memberService2")
    • ๋ชจ๋“  ์ž๋ฐ” ํด๋ž˜์Šค๋“ค์„ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”ํ•˜๋ฉด ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ํ•„์š”ํ•œ ์œ„์น˜๋ถ€ํ„ฐ ํƒ์ƒ‰ํ•˜๋„๋ก ์‹œ์ž‘ ์œ„์น˜๋ฅผ ์ง€์ • ํ•  ์ˆ˜ ์žˆ๋‹ค
      @ComponentScan(
      		basePackages = "hello.core", // {"hello.core", "hello.service"} ์—ฌ๋Ÿฌ ์œ„์น˜ ์ง€์ •
      )
    • basePackageClasses : ์ง€์ •ํ•œ ํด๋ž˜์Šค์˜ ํŒจํ‚ค์ง€๋ฅผ ํƒ์ƒ‰ ์‹œ์ž‘ ์œ„์น˜๋กœ ์ง€์ •
    • Default : @ComponentScan์ด ๋ถ™์€ ์„ค์ • ์ •๋ณด ํด๋ž˜์Šค์˜ ํŒจํ‚ค์ง€๊ฐ€ ์‹œ์ž‘ ์œ„์น˜
  • @Autowired

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

    • @Controller : ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ธ์‹
    • @Repository : ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์œผ๋กœ ์ธ์‹, ๋ฐ์ดํ„ฐ ๊ณ„์ธต์˜ ์˜ˆ์™ธ๋ฅผ ์Šคํ”„๋ง ์˜ˆ์™ธ๋กœ ๋ณ€ํ™˜ โ†’ DB์˜ ๋ณ€๊ฒฝ์„ ์ž์œ ๋กญ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด
    • @Configuration : ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด๋กœ ์ธ์‹, ์Šคํ”„๋ง ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค์„ ์œ ์ง€ํ•˜๋„๋ก ์ฒ˜๋ฆฌ
    • @Service : ๊ฐœ๋ฐœ์ž๋“ค์ด ๋น„์ฆˆ๋‹ˆ์Šค ๊ณ„์ธต์„ ์ธ์‹ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋œ๋‹ค.

์Šคํ”„๋ง ๋นˆ ์ค‘๋ณต ๋“ฑ๋ก

  1. ์ž๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก
    • ์Šคํ”„๋ง์—์„œ ConflictingBeanDefinitionException ์˜ˆ์™ธ ๋ฐœ์ƒ
  2. ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก
    • ์ˆ˜๋™ ๋นˆ์ด ์ž๋™ ๋นˆ์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜๋™ ๋นˆ์ด ์šฐ์„  ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„๋‹ค.
    • ํ•˜์ง€๋งŒ ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋„๋ก ๊ธฐ๋ณธ ๊ฐ’์„ ์„ค์ •ํ•ด๋‘์—ˆ๋‹ค.
    • application.properties ํŒŒ์ผ์— ์˜ค๋ฅ˜๋ฐœ์ƒ์ด ๋‚˜์˜ค๋Š” ๋กœ๊ทธ์ธ spring.main.allow-bean-definition-overriding=true ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋‚˜์ง€์•Š๊ณ  ์˜ค๋ฒ„๋ผ์ด๋”ฉ์ด ๋˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•„ํ„ฐ

  • ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์˜ ๋Œ€์ƒ์„ ์ถ”๊ฐ€, ์ œ์™ธ ์‹œํ‚จ๋‹ค.
@Configuration
    @ComponentScan(
            includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
            excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
    )
    static class ComponentFilterAppConfig{
    }
  • IncludeFilter๋กœ ์‚ฌ์šฉํ•  Annotation๊ณผ ExcludeFilter๋กœ ์‚ฌ์šฉํ•  Annotation๋ฅผ ๊ฐ๊ฐ ์„ ์–ธํ•œ ํ›„ ์ œ์™ธ ๋˜๋Š” ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ ํด๋ž˜์Šค์— ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ธ๋‹ค.
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MyIncludeComponent {
    }

โœ”๏ธ ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž…

๋‹ค์–‘ํ•œ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ๋ฐฉ๋ฒ•

  • ์ƒ์„ฑ์ž ์ฃผ์ž…
    • ์ƒ์„ฑ์ž ํ˜ธ์ถœ ์‹œ์ ์— ๋”ฑ 1๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ด ๋ณด์žฅ
    • ๋ถˆ๋ณ€, ํ•„์ˆ˜ ์˜์กด๊ด€๊ณ„์— ์‚ฌ์šฉ
    • โ€ป ์ƒ์„ฑ์ž๊ฐ€ 1๊ฐœ์ผ ๊ฒฝ์šฐ @Autowired๋ฅผ ์ƒ๋žตํ•ด๋„ ์ž๋™ ์ฃผ์ž…
  • ์ˆ˜์ •์ž ์ฃผ์ž… (Setter ์ฃผ์ž…)
    • ์ˆ˜์ •์ž(Setter) ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•

    • ์„ ํƒ, ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ์˜์กด๊ด€๊ณ„์— ์‚ฌ์šฉ

    • @Autowired์˜ ๊ธฐ๋ณธ๋™์ž‘์€ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ๋Œ€์ƒ์ด ์—†์–ด๋„ ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” @Autowired(required=false)

      private MemberRepository memberRepository;
      @Autowired
      public void setMemberRepository(MemberRepository memberRepository){
      			this.memberRepository = memberRepository;
      }
  • ํ•„๋“œ ์ฃผ์ž…
    • ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜์ง€๋งŒ ์™ธ๋ถ€์—์„œ ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.
    • DI ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์—†์œผ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†๋‹ค. โ†’ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ˆœ์ˆ˜ ์ž๋ฐ”์ฝ”๋“œ๋กœ๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Setter ๋ฉ”์„œ๋“œ๋ฅผ ๋”ฐ๋กœ ์„ ์–ธํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.
  • ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ ์ฃผ์ž…
    • ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

Autowired ์˜ต์…˜ ์ฒ˜๋ฆฌ

  • @Autowired(required=false) : ์ž๋™ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด ์ˆ˜์ •์ž ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • @Nullable : ์ž๋™ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด null์ด ์ž…๋ ฅ๋œ๋‹ค.
  • Optional<> : ์ž๋™ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด Optional.empty๊ฐ€ ์ž…๋ ฅ๋œ๋‹ค.

์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์„ ํƒํ•ด๋ผ!

  • ๋ถˆ๋ณ€
    • ๋Œ€๋ถ€๋ถ„์˜ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์€ ํ•œ๋ฒˆ ์ผ์–ด๋‚˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ์‹œ์ ๊นŒ์ง€ ์˜์กด๊ด€๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•  ์ผ์ด ์—†๋‹ค.
    • ์ˆ˜์ •์ž ์ฃผ์ž…์„ ์œ„ํ•ด์„œ๋Š” set ๋ฉ”์„œ๋“œ๋ฅผ ์—ด์–ด๋‘์–ด์•ผ ํ•˜๋Š”๋ฐ, ๋ณ€๊ฒฝํ•˜๋ฉด ์•ˆ๋˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์—ด์–ด๋‘๋Š” ๊ฒƒ์€ ์ข‹์€ ์„ค๊ณ„ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋‹ค.
  • ์ˆ˜์ •์ž ์ฃผ์ž…์„ ํ•œ ์ƒํƒœ์—์„œ ์ˆœ์ˆ˜ํ•œ ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๊ฒฝ์šฐ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • final ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
    • ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๋Š” ์„ธ์ƒ์—์„œ ๊ฐ€์žฅ ๋น ๋ฅด๊ณ , ์ข‹์€ ์˜ค๋ฅ˜๋‹ค!

๋กฌ๋ณต๊ณผ ์ตœ์‹  ํŠธ๋ Œ๋“œ

  • ๋กฌ๋ณต ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ ์šฉ ๋ฐฉ๋ฒ• build.gradle ์— ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ ํ™˜๊ฒฝ ์ถ”๊ฐ€
    
    plugins {
    id 'org.springframework.boot' version '2.3.2.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
    }
    group = 'hello'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = '11'
    //lombok ์„ค์ • ์ถ”๊ฐ€ ์‹œ์ž‘
    configurations {
    compileOnly {
    extendsFrom annotationProcessor
    }
    }
    //lombok ์„ค์ • ์ถ”๊ฐ€ ๋
    repositories {
    mavenCentral()
    }
    dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    
    //lombok ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ ์‹œ์ž‘
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
    //lombok ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ ๋
    
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    }
    test {
    useJUnitPlatform()
    }
    1. Preferences(์œˆ๋„์šฐ File Settings) plugin lombok ๊ฒ€์ƒ‰ ์„ค์น˜ ์‹คํ–‰ (์žฌ์‹œ์ž‘)
    2. Preferences Annotation Processors ๊ฒ€์ƒ‰ Enable annotation processing ์ฒดํฌ (์žฌ์‹œ์ž‘)
    3. ์ž„์˜์˜ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  @Getter, @Setter ํ™•์ธ
  • ๋กฌ๋ณต ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” @RequiredArgsConstructor Annotation์„ ์‚ฌ์šฉํ•˜๋ฉด ๋กฌ๋ณต์ด ์ž๋ฐ”์˜ ์• ๋…ธํ…Œ์ด์…˜ ํ”„๋กœ์„ธ์„œ๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ด์šฉํ•ด์„œ ์ปดํŒŒ์ผ ์‹œ์ ์— final์ด ๋ถ™์€ ํ•„๋“œ๋ฅผ ๋ชจ์•„์„œ ์ƒ์„ฑ์ž๋ฅผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค.

์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ์‹œ ์กฐํšŒ ๋นˆ์ด 2๊ฐœ ์ด์ƒ์ผ ๊ฒฝ์šฐ - @Autowired ํ•„๋“œ๋ช… , @Qualifier, @Primary

  • ๋ฌธ์ œ ์ƒํ™ฉ
    • @Autowired๋Š” ํƒ€์ž…์œผ๋กœ ์กฐํšŒ โ†’ ac.getBean(DiscountPolicy.class) ์™€ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘
    • DiscountPolicy๋ฅผ ํ†ตํ•ด ๊ตฌ์ฒดํ™”๋œ ๋นˆ์ด ๋‘๊ฐœ ์ด์ƒ ์žˆ์„ ๊ฒฝ์šฐ ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž… ์‹œ NoUniqueBeanDefinitionException ์˜ค๋ฅ˜ ๋ฐœ์ƒ
    • ํ•˜์œ„ ํƒ€์ž…(๊ตฌ์ฒดํ™” ํƒ€์ž…)์„ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ DIP๋ฅผ ์œ„๋ฐฐํ•˜๊ณ  ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.
  • ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
    • Autowired ํ•„๋“œ ๋ช… ๋งค์นญ
      • Autowired๋Š” ํƒ€์ž… ๋งค์นญ์„ ์‹œ๋„ํ•˜๊ณ , ์ด ๋•Œ ์—ฌ๋Ÿฌ ๋นˆ์ด ์žˆ์„ ๊ฒฝ์šฐ ํ•„๋“œ ์ด๋ฆ„, ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์œผ๋กœ ๋นˆ ์ด๋ฆ„์„ ์ถ”๊ฐ€ ๋งค์นญํ•œ๋‹ค. โ†’ ํ•„๋“œ ์ด๋ฆ„์ด๋‚˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ์ฃผ์ž…ํ•˜๊ณ  ์‹ถ์€ ํด๋ž˜์Šค ์ด๋ฆ„๊ณผ ๋˜‘๊ฐ™์ด ์„ค์ •ํ•œ๋‹ค๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค๋กœ ๋งค์นญ๋œ๋‹ค.
    • @Qualifier
      1. ๋นˆ ๋“ฑ๋ก์‹œ @Qualifier๋ฅผ ๋ถ™์—ฌ์ค€๋‹ค.

        @Component
        @Qualifier("mainDiscountPolicy")
        public class RateDiscountPolicy implements DiscountPolicy {}
      2. ์ฃผ์ž… ์‹œ์— @Qualifier๋ฅผ ๋ถ™์—ฌ์ฃผ๊ณ  ๋“ฑ๋กํ•œ ์ด๋ฆ„์„ ์ ์–ด์ค€๋‹ค.

        @Autowired
        public OrderServiceImpl(MemberRepository memberRepository, 
        									@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
        		this.memberRepository = memberRepository;
        		this.discountPolicy = discountPolicy;
        }
    • @Primary
      • @Primary Annotation์ด ๋ถ™์€ ํด๋ž˜์Šค๊ฐ€ ์šฐ์„ ๊ถŒ์„ ๊ฐ€์ง„๋‹ค.
    • Qualifier์™€ Primary ์ค‘ Qualifier๊ฐ€ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๋‹ค.

Annotation ๋งŒ๋“ค๊ธฐ

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {
}

์กฐํšŒํ•œ ๋นˆ์ด ๋ชจ๋‘ ํ•„์š”ํ•  ๋•Œ List, Map

์˜ˆ) ํ• ์ธ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ• ์ธ์˜ ์ข…๋ฅ˜๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒฝ์šฐ

  • ์ฝ”๋“œ ๋ณด๊ณ  ์ดํ•ดํ•˜๊ธฐ!!
    public class AllBeanTest {
    
        @Test
        void findAllBean() {
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
            DiscountService discountService = ac.getBean(DiscountService.class);
            Member member = new Member(1L, "name", Grade.VIP);
            int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy");
    
            Assertions.assertThat(discountPrice).isEqualTo(1000);
    
            int rateDiscountPrice = discountService.discount(member, 20000, "rateDiscountPolicy");
    
            Assertions.assertThat(rateDiscountPrice).isEqualTo(2000);
        }
    
        static class DiscountService {
            private final Map<String, DiscountPolicy> policyMap;
            private final List<DiscountPolicy> policies;
    
            @Autowired
            public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
                this.policyMap = policyMap;
                this.policies = policies;
                System.out.println("policyMap = " + policyMap);
                System.out.println("policies = " + policies);
            }
    
            public int discount(Member member, int price, String discountCode) {
                DiscountPolicy discountPolicy = policyMap.get(discountCode);
                return discountPolicy.discount(member, price);
            }
        }
    }

์‹ค๋ฌด์—์„œ์˜ ์ž๋™, ์ˆ˜๋™ ๋“ฑ๋ก

  • ํŽธ๋ฆฌํ•œ ์ž๋™ ๊ธฐ๋Šฅ์„ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉ
  • ์›น์„ ์ง€์›ํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ, ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์žˆ๋Š” ์„œ๋น„์Šค, ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋“ฑ์˜ ์—…๋ฌด๋กœ์ง ๋นˆ์€ ์ž๋™ ๋“ฑ๋ก, ๊ธฐ์ˆ ์ ์ธ ๋ฌธ์ œ๋‚˜ ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ(AOP)๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ์ˆ  ์ง€์› ๋นˆ์€ ์ˆ˜๋™ ๋“ฑ๋ก
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ค‘์— ๋‹คํ˜•์„ฑ์„ ์ ๊ทน ํ™œ์šฉํ•  ๋•Œ (์˜ˆ โ†’์กฐํšŒํ•œ ๋นˆ์ด ๋ชจ๋‘ ํ•„์š”ํ•  ๋•Œ)๋Š” ์ˆ˜๋™๋“ฑ๋ก์„ ๊ณ ๋ฏผํ•ด๋ณด์ž - ์ž๋™ ๋“ฑ๋ก ์‹œ ๊ตฌํ˜„ ๊ฐ์ฒด๊ฐ€ ํ•œ๋ˆˆ์— ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ๊ทธ๋ž˜๋„ ์ž๋™๋“ฑ๋ก์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๊ฒฝ์šฐ ๊ฐ™์€ ์ถ”์ƒํ™” ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ ๊ตฌํ˜„์ฒด๋Š” ๊ฐ™์€ ํŒจํ‚ค์ง€์— ๋ฌถ์–ด๋‘์ž

โœ”๏ธ ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ

  • ์Šคํ”„๋ง ๋นˆ์˜ ์ด๋ฒคํŠธ ๋ผ์ดํ”„ ์‚ฌ์ดํด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ โ†’ ์Šคํ”„๋ง ๋นˆ ์ƒ์„ฑ โ†’ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… โ†’ ์ดˆ๊ธฐํ™” ์ฝœ๋ฐฑ โ†’ ์‚ฌ์šฉ โ†’ ์†Œ๋ฉธ์ „ ์ฝœ๋ฐฑ โ†’ ์Šคํ”„๋ง ์ข…๋ฃŒ
  • ์Šคํ”„๋ง ๋นˆ์€ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ๋๋‚ด๊ณ  ๋‚˜์„œ์•ผ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์ดˆ๊ธฐํ™” ์ž‘์—…์€ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ๋๋‚˜๊ณ  ๋‚˜์„œ ์‹คํ–‰๋˜์–ด์•ผํ•œ๋‹ค.
  • ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ดˆ๊ธฐํ™” ์ฝœ๋ฐฑ ์‹œ์ ์„ ์•Œ์•„์•ผํ•œ๋‹ค.

๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋ถ„๋ฆฌํ•˜์ž

์ƒ์„ฑ์ž์— ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋ฅผ ๋„ฃ์œผ๋ฉด ๋˜์ง€ ์•Š์„๊นŒ๋ผ๋Š” ์ƒ๊ฐ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ƒ์„ฑ์ž๋Š” ํ•„์ˆ˜์ •๋ณด(ํŒŒ๋ผ๋ฏธํ„ฐ)๋ฅผ ๋ฐ›๊ณ  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฑ…์ž„์„ ๊ฐ€์ง€๋ฉฐ, ์ดˆ๊ธฐํ™”๋Š” ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ ๊ฐ’๋“ค์„ ํ™œ์šฉํ•˜์—ฌ ์™ธ๋ถ€ ์ปค๋„ฅ์…˜์„ ์—ฐ๊ฒฐํ•˜๋Š” ๋“ฑ์˜ ๋ฌด๊ฑฐ์šด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ์ƒ์„ฑ์ž ์•ˆ์—์„œ ๋ฌด๊ฑฐ์šด ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ํ•จ๊ป˜ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋‚˜๋ˆ„๋Š” ๊ฒƒ์ด ์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์—์„œ ๋” ๋‚˜์„ ์ˆ˜ ์žˆ๋‹ค.

์ฝœ๋ฐฑ ์‹œ์ ์„ ์•„๋Š” ๋ฐฉ๋ฒ• 3๊ฐ€์ง€

1. ์ธํ„ฐํŽ˜์ด์Šค InitializingBean, DisposableBean

  • ํด๋ž˜์Šค์— InitializingBean, DisposableBean์„ Implementsํ•ด์„œ ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•œ ํ›„ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์€ ์ฝ”๋“œ๋ฅผ ๊ฐ ๋ฉ”์„œ๋“œ ์•ˆ์— ๋„ฃ๋Š”๋‹ค.
  • ๋‹จ์ 
    • ์Šคํ”„๋ง ์ „์šฉ ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•œ๋‹ค.
    • ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค
    • ๋‚ด๊ฐ€ ์ฝ”๋“œ๋ฅผ ๊ณ ์น  ์ˆ˜ ์—†๋Š” ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

2. ๋นˆ ๋“ฑ๋ก ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ ์ง€์ •

  • ์„ค์ • ์ •๋ณด์— Bean(initMethod= "init", destroyMethod= "close") ์ฒ˜๋Ÿผ ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํŠน์ง•
    • ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์ž์œ ๋กญ๊ฒŒ ์ค„ ์ˆ˜ ์žˆ๋‹ค.
    • ์Šคํ”„๋ง ๋นˆ์ด ์Šคํ”„๋ง ์ฝ”๋“œ์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋„ ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ์ถ”๋ก 
    • ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋Œ€๋ถ€๋ถ„ close , shutdown ์ด๋ผ๋Š” ์ด๋ฆ„์˜ ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    • @Bean์˜ destoryMethod ๋Š” ๊ธฐ๋ณธ๊ฐ’์ด (inferred) ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š”๋ฐ ์ด๋Š” close, shutdown ์ด๋ผ๋Š” ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ํ˜ธ์ถœ ํ•ด์ค€๋‹ค.

3. Annotation @PostConstruct, @PreDestroy

  • ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ์— ํ•ด๋‹น Annotation์„ ๋ถ™์ด๋ฉด ๋œ๋‹ค.
  • ์Šคํ”„๋ง์— ์ข…์†์ ์ธ ๊ธฐ์ˆ ์ด ์•„๋‹ˆ๋ผ ์ž๋ฐ” ํ‘œ์ค€ โ†’ ์Šคํ”„๋ง์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ์—์„œ๋„ ๋™์ž‘
  • ์ฝ”๋“œ๋ฅผ ๊ณ ์น  ์ˆ˜ ์—†๋Š” ์™ธ๋ถ€๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋Š” ์ ์šฉํ•  ์ˆ˜ ์—†๋‹ค. โ†’ 2๋ฒˆ ๋ฐฉ๋ฒ• ์‚ฌ์šฉ

โœ”๏ธ ๋นˆ ์Šค์ฝ”ํ”„

  • ๋นˆ ์Šค์ฝ”ํ”„๋Š” ๋ง ๊ทธ๋ž˜๋กœ ๋นˆ์ด ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„(๊ธฐ๊ฐ„)๋ฅผ ์˜๋ฏธํ•œ๋‹ค

์Šค์ฝ”ํ”„ ์ง€์ • ๋ฐฉ๋ฒ•

@Scope("singleton") , @Scope("prototype") ๊ณผ ๊ฐ™์ด Annotation์„ ๋ถ™์—ฌ์ฃผ๋ฉด ๋œ๋‹ค. ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ์‚ฌ์šฉ์‹œ ํ•ด๋‹น ํด๋ž˜์Šค์—, Bean Annotation์„ ์‚ฌ์šฉํ•œ ์ˆ˜๋™์ฃผ์ž… ์‹œ Bean Annotation์—.

์Šคํ”„๋ง์ด ์ง€์›ํ•˜๋Š” ์Šค์ฝ”ํ”„

  • ์‹ฑ๊ธ€ํ†ค: ๊ธฐ๋ณธ ์Šค์ฝ”ํ”„, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ๊ฐ€์žฅ ๋„“์€ ๋ฒ”์œ„์˜ ์Šค์ฝ”ํ”„
  • ํ”„๋กœํ† ํƒ€์ž…: ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ ์ƒ์„ฑ๊ณผ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…, ์ดˆ๊ธฐํ™”๊นŒ์ง€๋งŒ ๊ด€๋ฆฌํ•˜๊ณ  ๋”๋Š” ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ์Šค์ฝ”ํ”„(์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ๋๋‚˜๋Š” ๋™์‹œ์— ์ปจํ…Œ์ด๋„ˆ๋ฐ–์œผ๋กœ ๋˜์ ธ๋ฒ„๋ฆฐ๋‹ค.)
    • ์š”์ฒญ์ด ์˜ฌ ๋•Œ๋งˆ๋‹ค ํ•ญ์ƒ ์ƒˆ๋กœ์šด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    • ๋จผ์ € Destroy๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ์›น ๊ด€๋ จ ์Šค์ฝ”ํ”„
    • request : ์›น ์š”์ฒญ์ด ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐˆ๋•Œ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„
    • session: ์›น ์„ธ์…˜์ด ์ƒ์„ฑ๋˜๊ณ  ์ข…๋ฃŒ๋  ๋•Œ ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„
    • application: ์›น์˜ ์„œ๋ธ”๋ฆฟ ์ปจํ…์ŠคํŠธ์™€ ๊ฐ™์€ ๋ฒ”์œ„๋กœ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„

ํ”„๋กœํ† ํƒ€์ž… ์Šค์ฝ”ํ”„ - ์‹ฑ๊ธ€ํ†ค ๋นˆ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ ์‹œ ๋ฌธ์ œ์ 

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์š”์ฒญํ•˜๋ฉด ํ•ญ์ƒ ์ƒˆ๋กœ์šด ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์‹ฑ๊ธ€ํ†ค ๋นˆ๊ณผ ํ•จ๊ป˜(์‹ฑ๊ธ€ํ†ค ๋นˆ์— ์ฃผ์ž…ํ•ด์„œ) ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์‹ฑ๊ธ€ํ†ค ๋นˆ์ด ์ƒ์„ฑ๋  ๋•Œ๋งŒ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ์ผ์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ์‹ฑ๊ธ€ํ†ค ๋นˆ์€ ๊ณ„์†ํ•ด์„œ ๊ฐ™์€ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ฒŒ ๋œ๋‹ค.

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

  1. ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ ์ „์ฒด ์ฃผ์ž…

    ๋‹จ์ˆœํ•˜๊ฒŒ ApplicationContext(์ปจํ…Œ์ด๋„ˆ) ์ž์ฒด๋ฅผ ์‹ฑ๊ธ€ํ†ค ๋นˆ์— ์ฃผ์ž…ํ•ด์„œ ๋กœ์ง์„ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค getBean์„ ํ†ตํ•ด ๋นˆ์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ์ƒˆ๋กœ์šด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ƒ์„ฑํ•ด์ค€๋‹ค.

    • ์ด๋ ‡๊ฒŒ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…๋ฐ›๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ง์ ‘ ํ•„์š”ํ•œ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฐพ๋Š” ๊ฒƒ์„ Dependency Lookup (DL) ์˜์กด๊ด€๊ณ„ ํƒ์ƒ‰์ด๋ผ๊ณ  ํ•œ๋‹ค. - ์ง€์—ฐ ์ฃผ์ž…?ํ•  ๋•Œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    • ๋‹จ์ : ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์ข…์†์ ์ธ ์ฝ”๋“œ๊ฐ€ ๋˜๊ณ  , ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ค์›Œ ์ง„๋‹ค.
  2. ObjectFactory, ObjectProvider โ†’ DL์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ

    • ์ง€์ •ํ•œ ๋นˆ์„ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ฐพ์•„์ฃผ๋Š” DL์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ObjectProvider
    • ObjectFactory์— ๊ธฐ๋Šฅ์ด ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€๋œ ๊ฐ“์ด ObjectProvider
    • ์Šคํ”„๋ง์— ์˜์กดํ•˜๊ธด ํ•˜์ง€๋งŒ ๊ธฐ๋Šฅ์ด ๋‹จ์ˆœํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ mock์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค๊ธฐ ์‰ฝ๋‹ค.
  3. Provider

    • ์ž๋ฐ” ํ‘œ์ค€, DL ์„œ๋น„์Šค ์ œ๊ณต
    • ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

์›น ์Šค์ฝ”ํ”„

  • ์›น ํ™˜๊ฒฝ์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค.

  • ์Šคํ”„๋ง์ด ํ•ด๋‹น ์Šค์ฝ”ํ”„์˜ ์ข…๋ฃŒ์‹œ์ ๊นŒ์ง€ ๊ด€๋ฆฌํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

  • request: http ์š”์ฒญ ํ•˜๋‚˜๊ฐ€ ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊น” ๋–„๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„, ๊ฐ๊ฐ์˜ http ์š”์ฒญ๋งˆ๋‹ค ๋ณ„๋„์˜ ๋นˆ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ๊ด€๋ฆฌ๋œ๋‹ค.

  • session

  • application

  • websocket

Request ์Šค์ฝ”ํ”„ ๋งŒ๋“ค๊ธฐ

  • Request ์Šค์ฝ”ํ”„ ํด๋ž˜์Šค ์ฝ”๋“œ (์ฃผ์„ ํฌํ•จ)
    @Component
    @Scope("request")
    public class MyLogger {
        private String uuid;
        private String requestURL;
    
        //RequestURL ์€ ๋นˆ์ด ์ƒ์„ฑ๋˜๋Š” ์‹œ์ ์—๋Š” ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ์™ธ๋ถ€์—์„œ setter ๋กœ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค.
        public void setRequestURL(String requestURL) {
            this.requestURL = requestURL;
        }
    
        public void log(String message){
            System.out.println("[" + uuid + "]" + "[" + requestURL + "]" + message);
        }
    
        @PostConstruct
        public void init(){
            uuid = UUID.randomUUID().toString(); // ์ด ๋นˆ์€ Http ์š”์ฒญ ๋‹น ํ•˜๋‚˜ ์”ฉ ์ƒ์„ฑ๋˜๋ฏ€๋กœ UUID๋ฅผ ์ €์žฅํ•ด๋‘๋ฉด ๋‹ค๋ฅธ Http ์š”์ฒญ๊ณผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.
            System.out.println("[" + uuid + "] request scope bean create:" + this);
    
        }
    
        @PreDestroy
        public void close(){
            System.out.println("[" + uuid + "] request scope bean close:" + this);
        }
    }
  • Request ์Šค์ฝ”ํ”„๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” Https ์š”์ฒญ์ด ๋“ค์–ด์™€์•ผํ•˜๊ณ  ์š”์ฒญ์ด ๋“ค์–ด์˜ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ปจํŠธ๋กค๋Ÿฌ์™€ ์„œ๋น„์Šค ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

Request ์Šค์ฝ”ํ”„์™€ Provider(Provider ์‚ฌ์šฉ ์‹œ๊ธฐ)

  • MyLogger๋Š” Request ์Šค์ฝ”ํ”„์ด๊ธฐ ๋•Œ๋ฌธ์— Http ์š”์ฒญ์ด ๋“ค์–ด์™€์„œ ์Šคํ”„๋ง ๋นˆ์— ์˜ฌ๋ผ๊ฐ„๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜์Œ ์Šคํ”„๋ง์„ ๋„์šธ ๋•Œ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๋Š”๋‹ค.
  • ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด MyLogger ๋นˆ ๋Œ€์‹ ์— MyLogger๋นˆ์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š”(DL) ObjectProvider ๋นˆ์„ ์ฃผ์ž…ํ•œ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  Http ์š”์ฒญ์ด ๋“ค์–ด์˜ค๊ณ  ๋‚œ ํ›„ ObjectProvider๋ฅผ ํ†ตํ•ด MyLogger๋ฅผ ์ฐพ๋Š”๋‹ค.

Request ์Šค์ฝ”ํ”„์™€ ํ”„๋ก์‹œ

  • Provider๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ•  ๋•Œ์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•
  • @Scope(value="request" proxyMode= ScopedProxyMode.TARGET_CLASS)

โ†’ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด MyLogger์˜ ๊ฐ€์งœ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋‘๊ณ  Http ์š”์ฒญ๊ณผ ์ƒ๊ด€์—†์ด ๊ฐ€์งœ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋ฏธ๋ฆฌ ์ฃผ์ž…ํ•ด ๋‘˜ ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์š”์ฒญ์ด ์˜ค๋ฉด ๊ทธ๋•Œ ๋‚ด๋ถ€์—์„œ ์ง„์งœ ๋นˆ์„ ์š”์ฒญํ•˜๋Š” ์œ„์ž„ ๋กœ์ง์ด ๋“ค์–ด์žˆ๋‹ค.

๐Ÿ”ฅ Provider๋ฅผ ์‚ฌ์šฉํ•˜๋“ , ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋“  ์ค‘์š”ํ•œ ๊ฒƒ์€ ์ง„์งœ ๊ฐ์ฒด ์กฐํšŒ๋ฅผ ๊ผญ ํ•„์š”ํ•œ ์‹œ์ ๊นŒ์ง€ ์ง€์—ฐ์ฒ˜๋ฆฌ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ์ด๋Ÿฐ ํŠน๋ณ„ํ•œ scope๋Š” ๊ผญ ํ•„์š”ํ•œ ๊ณณ์—๋งŒ ์ตœ์†Œํ™”ํ•ด์„œ ์‚ฌ์šฉ

0๊ฐœ์˜ ๋Œ“๊ธ€