๐ŸŒ Backend/๐Ÿƒ Spring

Bean Scope๊ฐ€ ๋ญ˜๊นŒ?

DevPoong 2022. 7. 13. 21:00

1. Bean scope๋ž€?

  • ๋นˆ์ด ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„๋ฅผ ๋œปํ•œ๋‹ค. ์Šคํ”„๋ง ๋นˆ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹ฑ๊ธ€ํ†ค scope๋กœ ์ƒ์„ฑ๋œ๋‹ค.

2. ์Šคํ”„๋ง์ด ์ง€์›ํ•˜๋Š” ์Šค์ฝ”ํ”„ ์ข…๋ฅ˜

(1) ์‹ฑ๊ธ€ํ†ค: ๊ธฐ๋ณธ ์Šค์ฝ”ํ”„์ด๋ฉฐ, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ๊ฐ€์žฅ ๋„“์€ ๋ฒ”์œ„์˜ scope

(2) ํ”„๋กœํ† ํƒ€์ž…: ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ ์ƒ์„ฑ๊ณผ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…๊นŒ์ง€๋งŒ ๊ด€์—ฌํ•˜๊ณ  ๋”์ด์ƒ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ์งง์€ ๋ฒ”์œ„์˜ scope

(3) ์›น 

 

์‹ฑ๊ธ€ํ†ค ์Šค์ฝ”ํ”„๋ฅผ ์ œ์™ธํ•œ ์Šค์ฝ”ํ”„๋Š” ์ง„์งœ ํ•„์š”ํ•œ ๊ณณ์—์„œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํŽธํ•˜๋‹ค ๋ผ๋Š” ๋ง์„ ์‹œ์ž‘์œผ๋กœ ํ•œ๋ฒˆ ์ •๋ฆฌํ•ด๋ณด์ž!


3-1. Prototype Scope

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์กฐํšŒํ•˜๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ํ•ญ์ƒ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ prototype scope์˜ ๋นˆ์„ ์š”์ฒญํ•˜๋ฉด ๊ทธ๋•Œ์„œ์•ผ ์ƒˆ๋กœ์šด ๋นˆ์„ ์ƒ์„ฑํ•˜๊ณ  ํ•„์š”ํ•œ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•˜์—ฌ ๋นˆ์„ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค. ๊ทธ ํ›„์—๋Š” ๊ด€๋ฆฌ๋ฅผ ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ๋งˆ๋‹ค ์„œ๋กœ ๋‹ค๋ฅธ ์ƒˆ๋กœ์šด ๋นˆ์„ ๋งŒ๋“ค์–ด์„œ ์ค€๋‹ค.

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” Prototype Bean์„ ์ƒ์„ฑํ•˜๊ณ , DIํ•˜๊ณ , ์ดˆ๊ธฐํ™”๊นŒ์ง€๋งŒ ์ฒ˜๋ฆฌํ•œ๋‹ค.

 

ํด๋ผ์ด์–ธํŠธ์— Bean์„ ๋ฐ˜ํ™˜ํ•˜๊ณ ๋‚˜์„œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ๋”์ด์ƒ Prototype Bean์— ๋Œ€ํ•ด์„œ ๊ด€๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ด€๋ฆฌ ์ฑ…์ž„์€ ์ด์ œ ๋นˆ์„ ๋ฐ›์€ ํด๋ผ์ด์–ธํŠธ์— ์žˆ๋‹ค.

 

๋”ฐ๋ผ์„œ  @PreDestroy๊ฐ™์€ ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๋Š” ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.

 

3-2. Singleton Bean์—์„œ Prototype Bean์„ ์ฃผ์ž…๋ฐ›๋Š”๊ฒฝ์šฐ ๋ฌธ์ œ

 

๊ฐ€์ • ์ƒํ™ฉ

๋งŒ์•ฝ singletonBean์ด๋ผ๋Š” ์‹ฑ๊ธ€ํ†ค ๋นˆ์ด ๋‚ด๋ถ€์— prototypeBean์„ ๋ฉค๋ฒ„๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ ์‹œ์ ์— ํ•จ๊ป˜ ์ƒ์„ฑ๋˜๊ณ  ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ๋ฐœ์ƒํ•œ๋‹ค.

1. DI ์ž๋™ ์ฃผ์ž… ์‹œ์ ์— ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— prototypeBean์„ ์š”์ฒญํ•œ๋‹ค.

 

2. ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” prototypeBean์„ ์ƒ์„ฑํ•ด์„œ singletonBean์— ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  prototypeBean์— count๋ผ๋Š” ๋ฉค๋ฒ„๊ฐ€ ์žˆ๊ณ  ๊ธฐ๋ณธ ๊ฐ’์ด 0์ด๋‹ค.

์ด์ œ singletonBean์€ prototypeBean์„ ๋‚ด๋ถ€ ํ•„๋“œ์— ๋ณด๊ด€ํ•œ๋‹ค. (์ •ํ™•ํžˆ๋Š” ์ฐธ์กฐ๊ฐ’์„ ๋ณด๊ด€)

 

3. ํด๋ผ์ด์–ธํŠธ A๋Š” singletonBean์„ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์š”์ฒญํ•ด์„œ ๋ฐ›๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  singletonBean์˜ ๋กœ์ง์ค‘ ํ•˜๋‚˜์ธ prototypeBean์˜ count๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” addCount()๋ฅผ ๋‚ด๋ถ€์—์„œ ํ˜ธ์ถœํ•˜๋Š” singletonBean.logic()์„ ํ˜ธ์ถœํ•œ๋‹ค.

 

4. singletonBean์€ prototypeBean์˜ addCount()๋ฅผ  ํ˜ธ์ถœํ•ด์„œ prototypeBean์˜ count๋ฅผ ์ฆ๊ฐ€์‹œ์ผœ count๋Š” 1์ด ๋œ๋‹ค.

 

5. ํด๋ผ์ด์–ธํŠธ B๋Š” singletonBean์„ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์š”์ฒญํ•ด์„œ ๋ฐ›๋Š”๋‹ค. ์‹ฑ๊ธ€ํ†ค์ด๋ฏ€๋กœ ํ•ญ์ƒ ๊ฐ™์€ singletonBean์ด ๋ฐ˜ํ™˜๋œ๋‹ค.

singletonBean์ด ๋‚ด๋ถ€์— ๊ฐ€์ง€๊ณ  ์žˆ๋Š” prototypeBean์€ ์ด๋ฏธ ์ด์ „์— ์ฃผ์ž…์ด ๋๋‚œ ๋นˆ์ด๋‹ค. singletonBean์˜ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ์‹œ์ ์— ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์š”์ฒญํ•ด์„œ prototypeBean์ด ์ƒˆ๋กœ ์ƒ์„ฑ์ด ๋œ ๊ฒƒ์ด์ง€, ์‚ฌ์šฉ ํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๋Š”๊ฒŒ ์•„๋‹˜!

๋”ฐ๋ผ์„œ ์‹ฑ๊ธ€ํ†ค ๋นˆ์— ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์ด ๋‚ด๋ถ€ ํ•„๋“œ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ•ด์„œ ์‹ฑ๊ธ€ํ†ค ๋นˆ์ด ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ํ”„๋กœํ† ํƒ€์ž…๋นˆ์ด ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๋Š”๊ฒŒ ์•„๋‹˜.

 

6. ํด๋ผ์ด์–ธํŠธ B๋Š” singletonBean.logic()์„ ํ˜ธ์ถœํ•œ๋‹ค.

 

7. singletonBean.logic()์˜ ๋‚ด๋ถ€์—์„œ prototypeBean์˜ addCount()๋ฅผ ํ˜ธ์ถœํ•ด์„œ prototypeBean์˜ count๋ฅผ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค. ๋”ฐ๋ผ์„œ count๋Š” 2๊ฐ€ ๋œ๋‹ค.

 

๋ฌธ์ œ

ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์“ด๋‹ค๋ฉด ์ด๋Ÿฐ ์ƒํ™ฉ์„ ๊ธฐ๋Œ€ํ•˜๊ณ  ์“ฐ๋Š”๊ฒŒ ์•„๋‹ ๊ฒƒ์ด๋‹ค. ์ด๋Ÿด๊ฑฐ๋ฉด ์‹ฑ๊ธ€ํ†ค์„ ์“ฐ์ง€ ์™œ ํ”„๋กœํ† ํƒ€์ž…์„ ์“ฐ๊ฒ ๋‚˜?

 

์Šคํ”„๋ง์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์‹ฑ๊ธ€ํ†ค ๋นˆ์„ ์‚ฌ์šฉํ•œ๋‹ค.

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

 

ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ฃผ์ž… ์‹œ์ ์—๋งŒ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ์›ํ•ด์„œ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

 

ํ•ด๊ฒฐ๋ฒ•

 

1. Singletone Bean์ด Prototype์„ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์ƒˆ๋กœ ์š”์ฒญ์„ ํ•œ๋‹ค. 

    @Scope("singleton")
    static class SingletonBean{

        @Autowired
        ApplicationContext applicationContext;

        public int logic(){
            PrototypeBean prototypeBean = applicationContext.getBean(PrototypeBean.class);
            prototypeBean.addCount();
            int count = prototypeBean.getCount();
            return count;
        }
    }
  • ์˜์กด๊ด€๊ณ„๋ฅผ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…(DI) ๋ฐ›๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ด๋Ÿฐ ์‹์œผ๋กœ ์ง์ ‘ ํ•„์š”ํ•œ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฐพ๋Š” ๊ฒƒ์„ ์˜์กด๊ด€๊ณ„ ํƒ์ƒ‰ Dependency Lookup (DL) ์ด๋ผ๊ณ  ํ•œ๋‹ค.

  • ์ด๋Ÿฐ์‹์œผ๋กœ Spring์˜ ApplicationContext ์ „์ฒด๋ฅผ ์ฃผ์ž… ๋ฐ›์•„ ๋ฒ„๋ฆฌ๋ฉด, Spring Container์— ์ข…์†์ ์ด๊ฒŒ ๋˜๋ฒ„๋ฆฌ๊ณ  ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ค์›Œ์ง„๋‹ค.

2. ObjectFactory, ObjectProvider ์‚ฌ์šฉ

@Scope("singleton")
static class ClientBean{

    @Autowired
    private ObjectProvider<PrototypeBean> prototypeBeanProvider;

    public int logic(){
        PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }
}
  • ObjectProvider๊ฐ€ ObjectFactory๋ฅผ ์ƒ์†๋ฐ›๋Š” ๊ตฌ์กฐ๋กœ ๋‘˜ ๋‹ค getObject()๋ฅผ ํ†ตํ•ด ๋นˆ์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ๋Š” ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ๊ฐ€์ ธ์˜ค๋ฏ€๋กœ ํ•ญ์ƒ ์ƒˆ๋กœ์šด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ ์ƒ์„ฑ๋˜์–ด ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ObjectProvider๊ฐ€ ObjectFactory๋ณด๋‹ค ๊ธฐ๋Šฅ์„ ๋” ์ œ๊ณตํ•ด์ค€๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
  • ํ•˜์ง€๋งŒ ObjectProvider๋Š” ํ”„๋กœํ† ํƒ€์ž… ์ „์šฉ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์•ˆ๋˜๊ณ  ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด์„œ DL์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋„์™€์ฃผ๋Š” ๋Œ€๋ฆฌ์ž ์ •๋„๋กœ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
  • 1๋ฒˆ์ฒ˜๋Ÿผ์ด ์•„๋‹ˆ๋ผ ์šฐ๋ฆฌ๋Š” DL ์˜์กด๊ด€๊ณ„ ํƒ์ƒ‰ ์ •๋„์˜ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ๊ฑด๋ฐ ๊ทธ๊ฑธ ์ œ๊ณตํ•ด์ฃผ๋Š”๊ฒŒ ObjectProvider์ด๋‹ค.
  • ObjectFactory: ๋‹จ์ˆœํ•œ ๊ธฐ๋Šฅ๋งŒ ์ œ๊ณต, ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•„์š” X. ์Šคํ”„๋ง์— ์˜์กด
  • ObjectProvider: ObjectFactory๋ฅผ ์ƒ์†๋ฐ›์Œ, ์˜ต์…˜, ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ ๋“ฑ ํŽธ๋ฆฌํ•œ ๊ธฐ๋Šฅ์„ ๋งŽ์ด ์ œ๊ณต, ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•„์š” X, ์Šคํ”„๋ง์— ์˜์กด
import org.springframework.beans.factory.ObjectProvider;

์Šคํ”„๋ง์— ์˜์กด์ ์ด๋ผ๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

 

 

3. JSR-330 Provider

javax.inject.Provider๋ผ๋Š” JSR-330 ์ž๋ฐ” ํ‘œ์ค€์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด 'javax.inject:javax.inject:1' ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ gradle์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•จ.

implementation 'javax.inject:javax.inject:1'

 

import javax.inject.Provider;

@Scope("singleton")
static class ClientBean{

    @Autowired
    private Provider<PrototypeBean> prototypeBeanProvider;

    public int logic(){
        PrototypeBean prototypeBean = prototypeBeanProvider.get();
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }
}
  • Provider์˜ get()์„ ํ˜ธ์ถœํ•˜๋ฉด ๋‚ด๋ถ€์—์„œ๋Š” DL๊ฐœ๋…์œผ๋กœ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋นˆ์„ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์ž๋ฐ” ํ‘œ์ค€ ๋ฐฉ๋ฒ•์ด๊ณ  ๊ธฐ๋Šฅ์ด ์ •๋ง ๋‹จ์ˆœํ•ด์„œ ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ Mock ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค๊ธฐ ํ›จ์”ฌ ์‰ฝ๋‹ค.
  • ObjectProvider๋Š” ์Šคํ”„๋ง์— ์˜์กด์ ์ด๊ณ  ๋‹ค๋ฅธ ๊ธฐ๋Šฅ๋“ค์ด ๋งŽ์ด ์žˆ๋˜ ๋ฐ˜๋ฉด, Provider๋Š” ์ •๋ง ํ•„์š”ํ•œ DL ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ ์ •๋„๋งŒ ์ œ๊ณตํ•œ๋‹ค.
  • ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • ์Šคํ”„๋ง์— ์˜์กด์ ์ด์ง€ ์•Š์œผ๋ฏ€๋กœ ์Šคํ”„๋ง์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ์—์„œ๋„ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

3-3. ์–ธ์ œ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์‚ฌ์šฉํ• ๊นŒ?

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

 

์ฐธ๊ณ ) ObjectProvider, Provider๋Š” ํ”„๋กœํ† ํƒ€์ž…์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ DL์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์— ์–ด๋””๋“ ์ง€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

 

3-4. ObjectProvider VS Provider

  • ObjectProvider๋Š” DL์„ ์œ„ํ•œ ํŽธ์˜ ๊ธฐ๋Šฅ์„ ์—ฌ๋Ÿฌ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์Šคํ”„๋ง ์™ธ์— ๋ณ„๋„์˜ gradle์— ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ํ•˜๋Š” ์ผ์ด ํ•„์š” ์—†์–ด์„œ ํŽธ๋ฆฌํ•˜๋‹ค.
  • Provider๋Š” ์Šคํ”„๋ง์— ์˜์กด์ ์ด์ง€ ์•Š๊ณ  ์ž๋ฐ” ํ‘œ์ค€์ด๋ฏ€๋กœ ์ฝ”๋“œ๋ฅผ ์Šคํ”„๋ง์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.(๊ฑฐ์˜ ์—†๋Š” ์ผ) ๊ทธ๋Ÿฐ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ด์•ผํ•˜๋Š” ๋ถˆํŽธํ•จ..

๋Œ€๋ถ€๋ถ„ ์Šคํ”„๋ง์ด ๋” ๋‹ค์–‘ํ•˜๊ณ  ํŽธ๋ฆฌํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์ฃผ๋ฏ€๋กœ ํŠน๋ณ„ํžˆ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•  ์ผ์ด ์—†๋‹ค๋ฉด, ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.


4. Web Scope

  • ์›น ํ™˜๊ฒฝ์—์„œ๋งŒ ๋™์ž‘
  • ํ”„๋กœํ† ํƒ€์ž…๊ณผ ๋‹ค๋ฅด๊ฒŒ ์Šคํ”„๋ง์ด ํ•ด๋‹น ์Šค์ฝ”ํ”„์˜ ์ข…๋ฃŒ์‹œ์ ๊นŒ์ง€ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋จ.

์›น ์Šค์ฝ”ํ”„ ์ข…๋ฅ˜

    1. request: HTTP ์š”์ฒญ์ด ํ•˜๋‚˜ ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐˆ ๋•Œ ๊นŒ์ง€ ์œ ์ง€.

                     ๊ฐ๊ฐ์˜ HTTP ์š”์ฒญ๋งˆ๋‹ค ๋ณ„๋„์˜ ๋นˆ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ๊ด€๋ฆฌ๋œ๋‹ค.

    2. session: HTTP Session๊ณผ ๋™์ผํ•œ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง„๋‹ค.

    3. application: ์›น์˜ Servletcontext์™€ ๋™์ผํ•œ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง„๋‹ค.

    4. websocket: ์›น Socket๊ณผ ๋™์ผํ•œ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง„๋‹ค.

 

4-1. Request Scope Example

web scope๋Š” ์›น ํ™˜๊ฒฝ์—์„œ๋งŒ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— web ํ™˜๊ฒฝ์ด ๋™์ž‘ํ•˜๋„๋ก ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

implementation 'org.springframework.boot:spring-boot-starter-web'

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด Spring Boot๋Š” ๋‚ด์žฅ ํ†ฐ์บฃ ์„œ๋ฒ„๋ฅผ ํ™œ์šฉํ•ด์„œ ์›น ์„œ๋ฒ„์™€ ์Šคํ”„๋ง์„ ํ•จ๊ป˜ ์‹คํ–‰์‹œํ‚จ๋‹ค.

 

์ฐธ๊ณ ) ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์—†์„ ๋•Œ๋Š” AnnotationConfigApplicationContext๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ๋™ํ•˜์ง€๋งŒ, ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ์›น๊ณผ ๊ด€๋ จ๋œ ์ถ”๊ฐ€ ์„ค์ •๊ณผ ํ™˜๊ฒฝ๋“ค์ด ํ•„์š”ํ•˜๋ฏ€๋กœ AnnotationConfigServletWebServerApplicationContext๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ๋™ํ•œ๋‹ค.

 

์˜ˆ์ œ ์„ค๋ช… : ๋™์‹œ์— ์—ฌ๋Ÿฌ HTTP ์š”์ฒญ์ด ์˜ค๋ฉด ์ •ํ™•ํžˆ ์–ด๋–ค ์š”์ฒญ์ด ๋‚จ๊ธด ๋กœ๊ทธ์ธ์ง€ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์–ด๋ ค์šฐ๋ฏ€๋กœ request scope๋ฅผ ์ด์šฉํ•˜์—ฌ UUID๋ฅผ ๋กœ๊ทธ ๋ฌธ์žฅ์— ์ถ”๊ฐ€ํ•˜์—ฌ ์ •ํ™•ํ•œ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ์˜ˆ์ œ.

 

MyLogger์— requestURL์„ ์ €์žฅํ•ด๋‘๋Š”๋ฐ MyLogger๋Š” ์Šค์ฝ”ํ”„๊ฐ€ request์ด๋ฏ€๋กœ HTTP ์š”์ฒญ ๋‹น ๊ฐ๊ฐ ๊ตฌ๋ถ„๋˜๋ฏ€๋กœ ๋‹ค๋ฅธ HTTP ์š”์ฒญ ๋•Œ๋ฌธ์— ๊ฐ’์ด ์„ž์ด๋Š” ๊ฑฑ์ •์€ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

@Component
@Scope(value = "request")
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 scope bean create: " + this);
    }

    @PreDestroy
    public void close(){
        System.out.println("[" + uuid + "] request scope bean close: " + this);
    }
}
@Controller
@RequiredArgsConstructor
public class LogDemoController {

    private final LogDemoService logDemoService;
    private final MyLogger myLogger;

    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request){
        String requestURL = request.getRequestURL().toString();
        myLogger.setRequestURL(requestURL);

        myLogger.log("controller test");
        logDemoService.logic("testId");
        return "OK";
    }
}
@Service
@RequiredArgsConstructor
public class LogDemoService {
    private final MyLogger myLogger;
    public void logic(String id) {
        myLogger.log("service id = " + id);
    }
}
  • request scope๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ requestURL๊ฐ™์€ ๋ชจ๋“  ์ •๋ณด๋ฅผ ์„œ๋น„์Šค ๊ณ„์ธต์œผ๋กœ ๋„˜๊ธฐ๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋งŽ์•„์„œ ์ง€์ €๋ถ„ํ•ด์ง€๊ณ  ์›น๊ณผ ๊ด€๋ จ์—†๋Š” ์„œ๋น„์Šค ๊ณ„์ธต์— ์ด๋Ÿฌํ•œ ์ •๋ณด๋“ค์ด ๋“ค์–ด์˜ค๋Š” ๊ฒƒ์€ ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค. 
  • ์›น๊ณผ ๊ด€๋ จ๋œ ๋ถ€๋ถ„์€ ์ปจํŠธ๋กค๋Ÿฌ๊นŒ์ง€๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.
  • ์„œ๋น„์Šค ๊ณ„์ธต์€ ์›น ๊ธฐ์ˆ ์— ์ข…์†๋˜์ง€ ์•Š๊ณ  ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์—์„œ ์ข‹๋‹ค.
  • MyLogger๋ฅผ request scope๋กœ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ์™€ ๊ณ„์ธต์„ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด๋Œ€๋กœ ์‹คํ–‰ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

request Scope ๊ด€๋ จํ•ด์„œ ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋ฌธ์ œ

์™œ๋ƒํ•˜๋ฉด request scope๋Š” ์œ„์—์„œ ๋งํ–ˆ๋“ฏ์ด ์‚ฌ์šฉ์ž์˜ http ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ ๋นˆ์ด ์ƒ์„ฑ๋œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ ์š”์ฒญ์ด ๋“ค์–ด์˜ค์ง€๋ฅผ ์•Š์•˜๋Š”๋ฐ Controller์™€ Service์— ์ž๋™ ์ฃผ์ž…ํ•ด์ฃผ๋ ค๊ณ  ํ•˜๋‹ˆ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š” ๊ฒƒ์ด๋‹ค.

๋”ฐ๋ผ์„œ request scope์˜ ๋นˆ์„ ๋ฐ›๋Š” ๊ฒƒ์„ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์ด ์ž…๋ ฅ๋  ๋•Œ๋กœ ๋ฏธ๋ค„์•ผ ํ•œ๋‹ค. ๋ฌด์—‡์„ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ?

 

 

๋ฌธ์ œ ํ•ด๊ฒฐ๋ฒ•

1. ObjectProvider ์‚ฌ์šฉ

ObjectProvider๋ฅผ ์ด์šฉํ•˜์—ฌ HTTP ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ getObjectํ•ด์„œ DLํ•˜์—ฌ ๋นˆ์„  ์ฐพ์•„์˜จ๋‹ค.

ObjectProvider.getObject()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ์ ์—๋Š” HTTP ์š”์ฒญ์ด ์ง„ํ–‰์ค‘์ด๋ฏ€๋กœ request scope์˜ ๋นˆ์˜ ์ƒ์„ฑ์ด ์ •์ƒ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ ์ฐพ์•„์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ž„.

@Controller
@RequiredArgsConstructor
public class LogDemoController {

    private final LogDemoService logDemoService;
    private final ObjectProvider<MyLogger> myLoggerProvider;

    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request){
        String requestURL = request.getRequestURL().toString();

        MyLogger myLogger = myLoggerProvider.getObject();
        myLogger.setRequestURL(requestURL);

        myLogger.log("controller test");
        logDemoService.logic("testId");
        return "OK";
    }
}

์œ„์™€ ๊ฐ™์ด Service๋„ ObjectProvider๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

 

2. Proxy ์‚ฌ์šฉ(์›น ์Šค์ฝ”ํ”„์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฑด ์•„๋‹˜)

MyLogger์˜ ๋Œ€๋ฆฌ์ž(๊ฐ€์งœ) Proxy ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋‘๊ณ  HTTP request์™€ ์ƒ๊ด€ ์—†์ด ๊ฐ€์งœ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋‹ค๋ฅธ ๋นˆ์— ๋ฏธ๋ฆฌ ์ฃผ์ž…ํ•ด ๋‘˜ ์ˆ˜ ์žˆ๋‹ค. 

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {

    private String uuid;
    private String requestURL;
    
    ...
}

Scope์— proxyMode ์˜ต์…˜์„ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

- ์ ์šฉ ๋Œ€์ƒ(์—ฌ๊ธฐ์„œ๋Š” MyLogger)์ด class์ด๋ฉด TARGET_CLASS

- ์ ์šฉ ๋Œ€์ƒ์ด ์ธํ„ฐํŽ˜์ด์Šค์ด๋ฉด INTERFACES ๋ฅผ ์„ ํƒ

๋‹จ์ง€ annotation ์„ค์ •์„ ์ถ”๊ฐ€ํ•œ ๊ฒƒ๋งŒ์œผ๋กœ ์›๋ณธ ๊ฐ์ฒด๋ฅผ Proxy๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ์„œ ๋‹คํ˜•์„ฑ๊ณผ DI ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ฐ€์ง„ ํฐ ์žฅ์ ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 ๋กœ๊ทธ๋ฅผ ์ฐ์–ด๋ณด๋ฉด CGLIB ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ๋‚ด ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ ๊ฐ€์งœ Proxy ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ฃผ์ž…ํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

  • @Scope์˜ proxMode๋ฅผ ์„ค์ •ํ•˜๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” CGLIB๋ผ๋Š” ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ MyLogger๋ฅผ ์ƒ์†๋ฐ›์€ ๊ฐ€์งœ Proxy ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— myLogger๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ง„์งœ ๋Œ€์‹ ์— ๊ฐ€์งœ Proxy ๊ฐ์ฒด๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.
  • ๋”ฐ๋ผ์„œ DI ์‹œ์—๋„ ์ด ๊ฐ€์งœ Proxy ๊ฐ์ฒด๊ฐ€ ์ฃผ์ž…๋œ๋‹ค.

๋Œ€๋ฆฌ์ž(๊ฐ€์งœ) Proxy ๊ฐ์ฒด๋Š” ์š”์ฒญ์ด ์˜ค๋ฉด ๊ทธ๋•Œ์„œ์•ผ ๋‚ด๋ถ€์—์„œ ์ง„์งœ Bean์„ ์š”์ฒญํ•˜๋Š” ์œ„์ž„ logic์ด ๋“ค์–ด์žˆ๋‹ค.

  • ๊ฐ€์งœ Proxy Bean์€ ๋‚ด๋ถ€์— ์‹ค์ œ MyLogger์˜ ์ง„์งœ Bean์„ ์ฐพ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ MyLogger.logic()์„ ํ˜ธ์ถœํ•˜๋ฉด ์‹ค์ œ๋กœ๋Š” ๊ฐ€์งœ Proxy ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒƒ์ด๋‹ค.
  • ๊ฐ€์งœ Proxy ๊ฐ์ฒด๋Š” request scope์˜ ์ง„์งœ myLogger.logic()์„ ๋‚ด๋ถ€์—์„œ ํ˜ธ์ถœํ•œ๋‹ค.
  • ๊ฐ€์งœ Proxy ๊ฐ์ฒด๋Š” ์œ„์—์„œ ๋งํ–ˆ๋“ฏ์ด ์›๋ณธ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ ๋งŒ๋“ค์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ์ž…์žฅ์—์„œ๋Š” ์›๋ณธ์ธ์ง€ ์•„๋‹Œ์ง€๋„ ๋ชจ๋ฅด๊ฒŒ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. (๋‹คํ˜•์„ฑ ๊ฐœ๋…) 

 

Proxy ๊ตฌ๋™ ๋ฐฉ์‹ ์ •๋ฆฌ

1. CGLIB๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋‚ด ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์€ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ฃผ์ž…ํ•œ๋‹ค.

2. ์ด ๊ฐ€์งœ Proxy ๊ฐ์ฒด๋Š” ์‹ค์ œ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ๊ทธ๋•Œ ๋‚ด๋ถ€์—์„œ ์‹ค์ œ ๋นˆ์„ ์š”์ฒญํ•˜๋Š” ์œ„์ž„ ๋กœ์ง์ด ๋“ค์–ด์žˆ๋‹ค.

3. ๊ฐ€์งœ Proxy ๊ฐ์ฒด๋Š” ์‹ค์ œ request scope์™€๋Š” ๊ด€๊ณ„ ์—†์ด ๊ทธ๋ƒฅ  ๊ฐ€์งœ์ด๊ณ  ๋‚ด๋ถ€์— ๋‹จ์ˆœํ•œ ์œ„์ž„ ๋กœ์ง์ด ์žˆ๋Š”๋ฐ ์‹ฑ๊ธ€ํ†ค ์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์‹ค์ œ๋กœ๋Š” ๋‚ด๋ถ€์—์„œ๋Š” ์‹ฑ๊ธ€ํ†ค์ด ์•„๋‹ˆ๋ฏ€๋กœ ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค.

 

Proxy ๊ฐ์ฒด ๋•๋ถ„์— ํด๋ผ์ด์–ธํŠธ๋Š” ๋งˆ์น˜ ์‹ฑ๊ธ€ํ†ค ๋นˆ์„ ์‚ฌ์šฉํ•˜๋“ฏ์ด ํŽธ๋ฆฌํ•˜๊ฒŒ request scope๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ฐธ๊ณ ) Provider๋ฅผ ์‚ฌ์šฉํ•˜๋˜์ง€ Proxy๋ฅผ ์‚ฌ์šฉํ•˜๋˜์ง€ ํ•ต์‹ฌ ์•„์ด๋””์–ด์ธ ์ง„์งœ ๊ฐ์ฒด ์กฐํšŒ๋ฅผ ๊ผญ ํ•„์š”ํ•œ ์‹œ์ ๊นŒ์ง€ ์ง€์—ฐ์ฒ˜๋ฆฌํ•œ๋‹ค๋Š”๊ฒŒ ์ค‘์š”ํ•˜๋‹ค.