[Spring] Bean Scope

Goghยท2023๋…„ 1์›” 2์ผ
0

Spring

๋ชฉ๋ก ๋ณด๊ธฐ
8/23

๐ŸŽฏ ๋ชฉํ‘œ : Bean Scope์˜ ์ดํ•ด

๐Ÿ“’ Bean Scope

๐Ÿ“Œ ๋นˆ์˜ ์ƒ๋ช…์ฃผ๊ธฐ

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ์˜ Bean Scope์˜ ๊ธฐ๋ณธ ๊ฐ’์€ singleton์ด๋‹ค.
  • ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋Š” ์ปจํ…Œ์ด๋„ˆ์˜ ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ์ƒ์„ฑ๋˜๊ณ , ์ปจํ…Œ์ด๋„ˆ์˜ ์†Œ๋ฉธ ์ „ ์ธ์Šคํ„ด์Šค๋„ ์†Œ๋ฉธ๋œ๋‹ค.
  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ -> ์Šคํ”„๋ง ๋นˆ ์ƒ์„ฑ -> ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… -> ์ดˆ๊ธฐํ™” ์ฝœ๋ฐฑ -> ์‚ฌ์šฉ -> ์†Œ๋ฉธ์ „ ์ฝœ๋ฐฑ -> ์Šคํ”„๋ง ์ข…๋ฃŒ
  • ์ดˆ๊ธฐํ™” ์ฝœ๋ฐฑ : ๋นˆ์ด ์ƒ์„ฑ๋˜๊ณ , ๋นˆ์˜ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ์™„๋ฃŒ ๋œ ํ›„ ํ˜ธ์ถœ
  • ์†Œ๋ฉธ์ „ ์ฝœ๋ฐฑ : ๋นˆ์ด ์†Œ๋ฉธ ๋˜๊ธฐ ์ง์ „์— ํ˜ธ์ถœ
  • ์Šคํ”„๋ง์€ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋นˆ์˜ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ์„ ์ง€์›ํ•œ๋‹ค.
    • ์ธํ„ฐํŽ˜์ด์Šค(InitializingBean, DisposableBean)
    • ์„ค์ • ์ •๋ณด์— ์ดˆ๊ธฐํ™” ๋ฉ”์†Œ๋“œ ์ข…๋ฃŒ ๋ฉ”์†Œ๋“œ ์ง€์ • (init(), close() - ์ž๋™์œผ๋กœ ์ฐพ์•„ ์ฝœ๋ฐฑํ•จ)
    • @PostConstruct @PreDestroy ์–ด๋…ธํ…Œ์ด์…˜
      1. ์ตœ์‹  ์Šคํ”„๋ง์—์„œ์˜ ๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•.
      2. ์Šคํ”„๋ง์— ์ข…์†์ ์ธ ๊ธฐ์ˆ ์ด ์•„๋‹ˆ๋ผ JSR-250 ์žํŒŒ ํ‘œ์ค€ ๊ธฐ์ˆ ์ด๋‹ค.
      3. ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์ž˜ ์–ด์šธ๋ฆฌ๋ฉฐ, ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋Š” ์ ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค. ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” @Bean(initMethod, destroyMethod)์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ฒ ๋‹ค.

๐Ÿ“Œ ๋นˆ ์Šค์ฝ”ํ”„

  • Singleton : ๊ธฐ๋ณธ๊ฐ’, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€๋œ๋‹ค.
  • Prototype : ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ ์ƒ์„ฑ๊ณผ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…๊นŒ์ง€๋งŒ ๊ด€์—ฌํ•˜๊ณ  ๋”์ด์ƒ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋งค์šฐ ์งง๋‹ค
  • ์›น ๊ด€๋ จ
    • Request : ์›น ์š”์ฒญ์ด ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐˆ๋•Œ ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„.
    • Session : ์›น ์„ธ์…˜์ด ์ƒ์„ฑ๋˜๊ณ  ์ข…๋ฃŒ๋  ๋•Œ ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„.
    • Application : ์›น์˜ ์„œ๋ธ”๋ฆฟ ์ปจํ…์ŠคํŠธ์™€ ๊ฐ™์€ ๋ฒ”์œ„๋กœ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„.

๐Ÿ“Œ Prototype Scope

  • ํ”„๋กœํ†  ํƒ€์ž… ์Šค์ฝ”ํ”„ ๋นˆ์„ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์š”์ฒญํ•˜๋ฉด,
  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์ด๋•Œ, ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ƒ์„ฑํ•˜๊ณ , ํ•„์š”ํ•œ ์˜์กด ๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค.
  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์ƒ์„ฑํ•œ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์ดํ›„, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ฐ™์€ ์š”์ฒญ์ด ์˜ค๋ฉด ํ•ญ์ƒ ์ƒˆ๋กœ์šด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
public class PrototypeTest {

    @Test
    void test() {
        AnnotationConfigApplicationContext ac
                = new AnnotationConfigApplicationContext(ProtoTypeBean.class);
        System.out.println("find prototypeBean1");
        ProtoTypeBean bean1 = ac.getBean(ProtoTypeBean.class);
        System.out.println("find prototypeBean2");
        ProtoTypeBean bean2 = ac.getBean(ProtoTypeBean.class);

        System.out.println("bean1 = " + bean1);
        System.out.println("bean2 = " + bean2);
        Assertions.assertThat(bean1).isNotSameAs(bean2);
        ac.close();
        /* prototype๋Š” ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ข…๋ฃŒ ๋˜๋”๋ผ๋„ ์ปจํ…Œ์ด๋„ˆ์˜ ๊ด€๋ฆฌ ๋นˆ์ด ์•„๋‹ˆ๊ธฐ๋–„๋ฌธ์—
        *  destroy๊ฐ€ ํ˜ธ์ถœ ๋˜์ง€ ์•Š๋Š”๋‹ค
        * ์ฆ‰ ์ƒ์„ฑ๊ณผ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ๊ทธ๋ฆฌ๊ณ  ์ดˆ๊ธฐํ™” ๊นŒ์ง€๋งŒ ๊ด€์—ฌํ•œ๋‹ค.*/
    }
    @Scope("prototype")
    static class ProtoTypeBean {
        @PostConstruct
        public void init() {
            System.out.println("SingletonBean.init");
        }

        @PreDestroy
        public void destroy() {
            System.out.println("SingletonBean.destroy");
        }
    }
}
// ์ถœ๋ ฅ๊ฐ’
find prototypeBean1
PrototypeBean.init
find prototypeBean2
PrototypeBean.init
bean1 = hello.core.scope.PrototypeTest$ProtoTypeBean@55493582
bean2 = hello.core.scope.PrototypeTest$ProtoTypeBean@1a20270e
  • ํ”„๋กœํ†  ํƒ€์ž… ๋นˆ์„ ์กฐํšŒ์™€ ๋™์‹œ์— ์ดˆ๊ธฐํ™” ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ• ์ˆ˜ ์žˆ๋‹ค
  • ์ดˆ๊ธฐํ™”๊ฐ€ 2๋ฒˆ ์‹คํ–‰ ๋˜๋Š” ๊ฒƒ์„ ๋ณด๋ฉด, ์„œ๋กœ ๋‹ค๋ฅธ ๋นˆ์ด๋ผ๋Š” ๊ฒƒ๋„ ํ™•์ธ ํ• ์ˆ˜ ์žˆ๋‹ค.
  • ํ•˜์ง€๋งŒ, ํ”„๋กœํ†  ํƒ€์ž… ๋นˆ์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ƒ์„ฑ๊ณผ ์˜์กด ๊ด€๊ณ„ ์ฃผ์ž… ๊ทธ๋ฆฌ๊ณ  ์ดˆ๊ธฐํ™” ๊นŒ์ง€๋งŒ ๊ด€๋ฆฌํ•˜๊ณ , ๋”์ด์ƒ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ Destroy ๋ฉ”์†Œ๋“œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

๐Ÿ“Œ Singleton &ย Prototypeย 

  • ์‹ฑ๊ธ€ํ†ค ๋นˆ๊ณผ ํ”„๋กœํ†  ๋นˆ์ด ํ•จ๊ป˜ ์‚ฌ์šฉ๋  ๋•Œ๋Š” ์˜๋„ํ•œ ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„์ˆ˜๋„ ์žˆ๋‹ค.
  • ์‹ฑ๊ธ€ํ†ค ๋นˆ์ด ํ”„๋กœํ†  ๋นˆ์„ ์˜์กด ๊ด€๊ณ„ ์ฃผ์ž…์„ ๋ฐ›๊ฒŒ ๋˜์—ˆ์„๋•Œ,ย 
  • ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์€ ์‹ฑ๊ธ€ํ†ค ๋นˆ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•œ๋‹ค๋ฉด, ์‹ฑ๊ธ€ํ†ค ๋นˆ์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ๊ณผ ์ข…๋ฃŒ๊นŒ์ง€ ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ์กด์žฌ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœํ†  ๋นˆ์„ ์ฃผ์ž… ๋ฐ›์€์ฑ„๋กœ ์œ ์ง€ ๋  ๊ฒƒ์ด๋‹ค.
public class SingletonWithPrototypeTest1 {
	// TEST1
    @Test
    void singletonClientUsePrototype() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class, ClientBean.class);
        ClientBean bean1 = ac.getBean(ClientBean.class);
        int count1 = bean1.logic();
        assertThat(count1).isEqualTo(1);

        ClientBean bean2 = ac.getBean(ClientBean.class);
        int count2 = bean2.logic();
        assertThat(count2).isEqualTo(2);
		// ์ถœ๋ ฅ๊ฐ’
       // PrototypeBean.inithello.core.scope.SingletonWithPrototypeTest1$PrototypeBean@1e097d59
    }

    // TEST2
    @Test
    void singletonClientUseProviderPrototype() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class, ClientBean2.class);
        ClientBean2 bean1 = ac.getBean(ClientBean2.class);
        int count1 = bean1.logic();
        assertThat(count1).isEqualTo(1);

        ClientBean2 bean2 = ac.getBean(ClientBean2.class);
        int count2 = bean2.logic();
        assertThat(count2).isEqualTo(1);
        // ์ถœ๋ ฅ๊ฐ’
        //PrototypeBean.inithello.core.scope.SingletonWithPrototypeTest1$PrototypeBean@531f4093
        //PrototypeBean.inithello.core.scope.SingletonWithPrototypeTest1$PrototypeBean@373ebf74
    }

    @Scope("singleton")
    static class ClientBean {
        private final PrototypeBean prototypeBean;
        @Autowired
        public ClientBean(PrototypeBean prototypeBean) {
            this.prototypeBean = prototypeBean;
        }

        public int logic() {
            prototypeBean.addCount();
            int count = prototypeBean.getCount();
            return count;
        }
    }

    @Scope("singleton")
    static class ClientBean2 {
        private final Provider<PrototypeBean> prototypeBeanProvider;
        @Autowired
        ClientBean2(Provider<PrototypeBean> prototypeBeanProvider) {
            this.prototypeBeanProvider = prototypeBeanProvider;
        }

        public int logic() {
            PrototypeBean prototypeBean = prototypeBeanProvider.get();
            prototypeBean.addCount();
            int count = prototypeBean.getCount();
            return count;
        }
    }


    @Scope("prototype")
    static class PrototypeBean {
        private int count = 0;

        public void addCount() {
            count++;
        }

        public int getCount() {
            return count;
        }

        @PostConstruct
        public void init() {
            System.out.println("PrototypeBean.init"+this);
        }

        @PreDestroy
        public void destory() {
            System.out.println("PrototypeBean.destory");
        }
    }

}
  • PrototypeBean์„ ์˜์กด ๊ด€๊ณ„๋กœ ์ฃผ์ž… ๋ฐ›๋Š” ClientBean, ClientBean2 ๊ฐ€ ์žˆ๋‹ค.ย 
  • TEST1์„ ๋ณด๋ฉด, ClientBean์„ 2๋ฒˆ ํ˜ธ์ถœํ•˜๊ณ  ๊ฐ๊ฐ์˜ ๋นˆ์ด logic()์„ ํ˜ธ์ถœ ํ•˜๊ณ  ์žˆ๋‹ค.
  • ์ด๋•Œ, ์ฒซ๋ฒˆ์งธ logic() ํ˜ธ์ถœ๋•Œ count1์€ 1์ด ๋  ๊ฒƒ์ด๊ณ , count 2๋Š” 2๊ฐ€๋  ๊ฒƒ์ด๋‹ค.ย  ClientBean์˜ ๋นˆ์˜ ๊ฐ๊ฐ์˜ ํ˜ธ์ถœ๊ณผ ๋กœ์ง์˜ ํ˜ธ์ถœ์—๋Š” ์„œ๋กœ ์˜ํ–ฅ์„ ๋ฐ›๋Š”๊ฒƒ์„ ๊ธฐ๋Œ€ ํ•œ ๊ฒƒ์€์•„๋‹ˆ๋‹ค.
  • ClientBean ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด์ด๋ฏ€๋กœ, ์ฒซ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ๋•Œ ์ฃผ์ž…๋ฐ›์€ PrototypeBean์˜ ์˜์กด ๊ด€๊ณ„๋ฅผ ๊ณ„์† ์œ ์ง€ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.
  • ์„œ๋กœ ๋‹ค๋ฅธ ์š”์ฒญ์ด๋ฉฐ ์ฒซ ์š”์ฒญ์ด ๋‘๋ฒˆ์งธ ์š”์ฒญ์— ์˜ํ–ฅ์„ ๋ผ์น˜๋Š”๊ฒƒ์„ ๊ธฐ๋Œ€ ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ฑ๊ธ€ํ†ค๊ณผ ํ”„๋กœํ†  ํƒ€์ž…์˜ ๋นˆ์„ ํ•จ๊ป˜ ์“ฐ๊ฒŒ๋˜๋ฉด ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Javax.inject.Provider๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  • TEST2๋ฅผ ๋ณด๋ฉด getBean()์— ์˜ํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ํ”„๋กœํ†  ํƒ€์ž… ๋นˆ์ด ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธ ํ• ์ˆ˜ ์žˆ๋‹ค.
  • ClientBean2์—์„œ Provider์˜ get()์€ ๋‚ด๋ถ€์—์„œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋นˆ์„ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.
  • ์ด๋•Œ ์˜์กด ๊ด€๊ณ„๋ฅผ ์™ธ๋ถ€์—์„œ ์ฃผ์ž… ๋ฐ›๋Š”๊ฒƒ(DI)์ด ์•„๋‹ˆ๋ผ ์ง์ ‘ ํ•„์š”ํ•œ ์˜์กด ๊ด€๊ณ„๋ฅผ ์ฐพ๋Š” ๊ฒƒ์„ Dependency Lookup(DL)์ด๋ผ ํ•œ๋‹ค. ํ•„์š”ํ•œ ์˜์กด ๊ด€๊ณ„์™€ ์ง€์ •ํ•œ ํ”„๋กœํ†  ํƒ€์ž… ๋นˆ์„ ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋Œ€์‹  ์ฐพ์•„์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.ย 

๐Ÿ“Œย Request Scope

  • HTTP ์š”์ฒญ ํ•˜๋‚˜๊ฐ€ ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐˆ ๋•Œ ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„๋‹ค, ๊ฐ๊ฐ์˜ HTTP ์š”์ฒญ๋งˆ๋‹ค ๋ณ„๋„์˜ ๋นˆ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , ๊ด€๋ฆฌ ๋œ๋‹ค.
  • Request Scope์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด request scope๋กœ HTTP ์š”์ฒญ์‹œ์— ์ƒ์„ฑ๋˜๋Š” ์˜ˆ์ œ MyLogger ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค.
// MyLogger.java
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
/* ๊ฐ€์งœ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋‘๊ณ  ์ฃผ์ž…ํ•ด์ค€๋‹ค*/
public class MyLogger {
    private String uuid;
    private String requestURL;

    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();
        System.out.println("["+uuid+"]"+" request scop bean create "+this);
    }

    @PreDestroy
    public void close() {
        System.out.println("["+uuid+"]"+" request scop bean close "+this);
    }
}

// LogDemoController.java
@Controller
@RequiredArgsConstructor
public class LogDemoController {

    private final LogDemoService logDemoService;
    /* ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋ ๋•Œ request scope ๋นˆ์€ ์ƒ์„ฑ๋ ์ˆ˜๊ฐ€ ์—†๋‹ค
    *  Provider๋ฅผ ํ™œ์šฉํ•ด์„œ ํ•ด๊ฒฐ ํ•ด์•ผํ•œ๋‹ค
    *  ํ•˜์ง€๋งŒ MyLogger์—์„œ proxyMode๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Provider๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋„ ์—†์–ด์ง„๋‹ค*/
    private final MyLogger myLogger;

    @RequestMapping("/log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request) {
        String requestURL = request.getRequestURL().toString();
//        MyLogger myLogger = myLoggerProvider.getObject();
        /* ์ฃผ์ž…ํ•ด์ฃผ๋Š” ๊ฐ€์งœ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ํ™•์ธํ•ด๋ณด์ž */
        System.out.println("myLogger = " + myLogger.getClass());

        myLogger.setRequestURL(requestURL);
        myLogger.log("Controller Test");
        logDemoService.logic("testId");
        return "OK";
    }
}

//LogDemoService.java
@Service
@RequiredArgsConstructor
public class LogDemoService {
    /* ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋ ๋•Œ request scope ๋นˆ์€ ์ƒ์„ฑ๋ ์ˆ˜๊ฐ€ ์—†๋‹ค
     *  Provider๋ฅผ ํ™œ์šฉํ•ด์„œ ํ•ด๊ฒฐ ํ•ด์•ผํ•œ๋‹ค
     *  ํ•˜์ง€๋งŒ MyLogger์—์„œ proxyMode๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Provider๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋„ ์—†์–ด์ง„๋‹ค*/
//    private final ObjectProvider<MyLogger> myLoggerProvider;
    private final MyLogger myLogger;


    public void logic(String testId) {
//        MyLogger myLogger = myLoggerProvider.getObject();
        myLogger.log("Service Id = " + testId);
    }
}
  • MyLogger๋ฅผ ์˜์กด ๊ด€๊ณ„๋กœ ์ฃผ์ž… ๋ฐ›๋Š” LogDemoController์™€ LogDemoService๊ฐ€ ์žˆ๋‹ค.
  • request ์Šค์ฝ”ํ”„๋ฅผ ์„ค์ • ํ•ด์ฃผ๋Š”๋ฐ, proxyMode = ScopedProxyMode.TARGET_CLASS ์˜ต์…˜๊นŒ์ง€ ์„ค์ • ํ•ด ๋‘์—ˆ๋‹ค.
  • Proxy๋ฅผ ์•Œ์•„๋ณด๊ธฐ ์ „์—, request ์Šค์ฝ”ํ”„๋Š” HTTP ์š”์ฒญ์ด ์žˆ์„๋•Œ ์ƒ์„ฑ๋˜๋Š” ๋นˆ์ด๋ผ๊ณ  ํ–ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ, LogDemoController์™€ LogDemoService๋Š” MyLogger๋ฅผ ์˜์กดํ•˜๋Š” Bean ์ด๋ฉด์„œ, ์‹ฑ๊ธ€ํ†ค Bean์ด๋‹ค.
  • ์‹ฑ๊ธ€ํ†ค ๋นˆ์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ์ƒ์„ฑ๋˜๋Š” ์ธ์Šคํ„ด์Šค์ธ๋ฐ, HTTP ์š”์ฒญ์ด ์žˆ์„๋•Œ ์ƒ์„ฑ๋˜๋Š” MyLogger์˜ request ์Šค์ฝ”ํ”„ ๋นˆ์˜ ์˜์กด์„ฑ ์ฃผ์ž…์„ ๋ฐ›์„์ˆ˜ ์žˆ์„๊นŒ?
  • ๋งŒ์•ฝ Proxy ์„ค์ •์„ ํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๋งˆ์ฃผ์น˜๊ฒŒ ๋œ๋‹ค.
Error creating bean with name 'myLogger': Scope 'request' is not active for the
current thread; consider defining a scoped proxy for this bean if you intend to
refer to it from a singleton;
  • request scope ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋กœ ๋ถ€ํ„ฐ ์˜์กด ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์—๋Ÿฌ๋‹ค. ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋‹น์—ฐํ•œ ์• ๋Ÿฌ๋‹ค.
  • ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Prototype ์Šค์ฝ”ํ”„์—์„œ ํ™œ์šฉํ–ˆ๋˜ Provider๋ฅผ ํ™œ์šฉ ํ•ด ๋ณผ์ˆ˜ ์žˆ์„๊ฒƒ์ด๋‹ค.
  • ๋” ๋‚˜์•„๊ฐ€ Proxy ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ๋ฌธ์ œ๋ฅผ ๋” ์‰ฝ๊ฒŒ ํ•ด๊ฒฐ ํ• ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
  • proxyMode๋ฅผ ์„ค์ •ํ•ด ์ฃผ๊ณ ์ž ํ•œ๋‹ค๋ฉด, ์ ์šฉ๋Œ€์ƒ์ด ํด๋ž˜์Šค ์ผ๋•Œ TARGET_CLASS๋ฅผ ์„ ํƒํ•˜๊ณ , ์ ์šฉ ๋Œ€์ƒ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฉด INTERFACES๋ฅผ ์„ ํƒํ•˜๋ฉด ๋œ๋‹ค.
System.out.println("myLogger = " + myLogger.getClass());

// ์ถœ๋ ฅ๊ฐ’
// myLogger = class hello.core.common.MyLogger$$EnhancerBySpringCGLIB$$b68b726d
  • ์œ„์™€ ๊ฐ™์ด myLogger ๋นˆ์˜ ํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ์–ป์–ด ์ถœ๋ ฅํ•ด ๋ณด๋ฉด, CGLIB๋ผ๋Š” ๊ฒƒ์„ ๋ณผ์ˆ˜ ์žˆ๋‹ค.
  • CGLIB ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋จผ์ € ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•˜๊ณ , ์š”์ฒญ์ด ์˜ค๋ฉด ๊ทธ๋•Œ ๋‚ด๋ถ€์—์„œ ์ง„์งœ ๋นˆ ์ธ์Šคํ„ด์Šค๋ฅผ ์š”์ฒญํ•˜์—ฌ ์ฃผ์ž… ํ•ด์ค€๋‹ค.
  • ์ฆ‰, ๊ฐ€์งœ ๊ฐ์ฒด๋Š” ์‹ค์ œ request scope์™€ ๊ด€๊ณ„๋Š” ์—†๊ณ  ๋‚ด๋ถ€์— ์š”์ฒญ์ด ์™”์„๋•Œ ์ง„์งœ ๋นˆ์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ๋กœ์ง์ด ์žˆ๋‹ค๋Š” ๋ง์ด๋‹ค.
profile
์ปดํ“จํ„ฐ๊ฐ€ ํ• ์ผ์€ ์ปดํ“จํ„ฐ๊ฐ€

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