ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Bean 그리고 scope
    Back-end Developer/Server, Spring 2020. 6. 23. 18:49

    지난번 Bean이 무엇인지 간략하게 알아봤습니다.

    (IoC container, Bean 관련 개념이 아직 부족하시다면 간략히 이전 포스트 참고해 주세요.)

     

    Bean을 사용하는 이유 중 하나가 scope가 자동으로 singleton으로 설정되기 때문이라 말씀드렸습니다.

    오늘은 scope가 무엇이고, 그 종류와 각 종류별 특징에 관련한 내용을 알아볼까 합니다.

    (-> 이 글에서는 대표적인 두 가지 Singleton/Prototype와 관련한 내용을 포스팅 합니다.)

     

    우선 사전적인 정의를 한번 보겠습니다.

    Scope [skoʊp] 

    명사 (무엇을 하거나 이룰 수 있는) 기회[여지/능력] (=potential)
    명사 (주제 조직 활동 등이 다루는) 범위
    동사 (비격식) 샅샅이[자세히] 살피다

    이외에도 다양한 의미가 있으나, Bean의 scope 또한 일반적인 '범위'라는 의미를 갖습니다.

     

    일반적으로 코딩에서 쓰이는 전역/지역 변수나, 접근 한정자 등에서 쓰이는 범위의 개념과는 약간 다릅니다.

    전역/지역 변수와 접근 한정자는 영향을 미치는 범위라는 느낌이 강합니다.

    하지만, Bean의 scope는 해당 객체가 만드는 instance에 대한 성질을 나타냅니다.

     

    마지막에 다른 scope도 간략히 소개는 드리겠지만, 위에서 말씀드렸던 두가지만 우선 살펴보겠습니다.

    Singleton: Application 전반에 걸쳐 해당 Bean의 instance가 하나만 존재

    -> 즉, 객체가 인스턴스를 생성할 때마다 주솟값이 동일한 같은 인스턴스를 내놓습니다.

    Prototype: Bean이 intance를 생성할 때 매번 다른 instance를 제공.

     

    Singleton은 전체 범위에서 하나의 instance가 넓게 사용되며,

    Prototype 좁은 범위에서 여러개의 주소만 다른 instance가 사용됩니다.

    (뭐.. 거창하게 설명은 드렸지만, 별 내용은 아닙니다. ㅎㅎ 이해를 돕기위한 포석이랄까)

     

     

    Singleton (default)

    Singleton img (출처: spring docs)

    Singleton 설정 (안해도 됨)

    @Component
    @Scope("singleton")
    public class A {
        public A{ }
        
        ....
    }

     

    Spring docs를 찾아보면 Singleton을 아래와 같이 설명합니다.

    Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Spring container

     

    Bean에서 관리하는 인스턴스는 오직 하나이며, 모든 요청은 Spring container가 해당 빈과 매칭되는 인스턴스로 반환 한다.

    즉, Bean 관리 뿐만 아니라 인스턴스 반환을 Spring container가 직접 한다는 이야기 같네요.

    -> Java에서 String 상수 pool의 문자열을 다루는 것과 유사한 느낌이 듭니다.

     

    생각해보면 너무 당연한 이야기인 것이, Bean을 정리했던 저번 포스팅에서 Bean의 정의를 생각해보시면 됩니다.

    'Spring IoC container에 의해 관리되고 있는 객체'라고 했었죠.

     

    또한 조금 아래에 중요한 내용이 나옵니다.

     

    This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object.

     

    이렇게 생성된 단일 인스턴스는 Singleton bean cache에 저장되며, 이후 요청과 참조는 cache화 된 객체에서 처리한다.

    cache는 일반적으로 성능 향상을 위해 쓰기 때문에 빠르게 처리 될 수 있는 장점을 가지겠네요.

    또한, 컨테이너가 사라지면 Singleton bean도 제거됩니다.

    (GoF pattern의 singleton과는 다른 개념이니 주의하라는 문구도 쓰여있네요.)

     

     

    Prototype

    Prototype img (출처: spring docs)

    Prototype 설정

    @Component
    @Scope("prototype")
    public class A {
        public A{ }
        
        ....
    }

     

    이전 링크에서 조금 아래로 내려보시면 Prototye 관련 설명도 존재합니다.

    The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made. That is, the bean is injected into another bean or you request it through a getBean() method call on the container.

     

    non-Singleton, Prototype scope는 요청할 때마다 Bean에서 새로운 instance를 생성한다. 즉, Bean을 또 다른 Bean에 주입하거나 getBean()을 통해 container에 요청할 수 있다.

    -> Prototype Bean은 GC에 의해 제거됩니다.

     

     

    결론적으로 두 scope의 차이는 stateful/stateless라고 정의합니다.

    어떤 것이 stateful bean에 사용되고, stateless bean에 사용될까요?

     

    너무 당연하게도,

    매번 새로운 인스턴스를 만들어내는 Prototype가변적인 Bean에 적용하기 좋을 것이고,

    하나의 인스턴스로 전체적으로 사용하는 Singleton불변하는 Bean에 적용하기 좋겠네요.

    -> 가변 불변이라고 생각하시면 기억하기에도 이해하기에도 좋을 듯합니다.

     

     

     

    하지만, 이렇게 두가지 Bean을 사용하다보면 곤란한 경우가 생깁니다.

    Prototye, Singleton bean을 함께 쓰는 경우가 바로 그러한 상황인데요.
    2가지로 분류할 수 있습니다.

     

    Prototype이 Singleton을 가진 경우

    이 경우는 어떤 문제가 있을까요?

    생각을 조금만 해보시면, 별 문제가 없다는 것을 알 수 있습니다.

    Prototype 내 Singleton 구조도

    Prototype은 가변하는 주소를 갖겠지만, 해당 instance에 들어가는  Singleton instance는 동일한 것을 갖다 쓰면 되겠죠.

     

    이러한 동작은 우리가 옷을 입는 것과 비슷하다고 생각하시면 됩니다.

    의류가 Prototype이고, 사람의 몸이 Singleton이라 가정해볼게요.

    어제와 오늘 다른 옷을 입었다면, 옷에 의해 겉 모습이나 이미지는 바뀌겠죠?

    하지만, 옷에 의해 저희 몸이 함께 변하진 않습니다.

    (물론 꽉끼는 옷을 입거나하면 언젠간 변하겠지만 이런건 예외로 두고요.)

     

    엄청 들어맞는 예시는 아니지만, 예시 자체의 내용이 논리적으로 이상한 느낌도 없죠.

    어느정도 이해하셨길 바랍니다. :)

     

    Singleton이 Prototype을 가진 경우

    위의 경우가 문제가 아니었으니 이와 같은 경우가 문제가 되겠네요.

    이 또한 그림으로 포함관계를 보고 이해해볼게요.

    Singleton 내 Prototype 구조도

    이와 같은 경우

    이미 처음 Singleton Bean이 생성되었을 때, Prototype 또한 그때의 상태로 고정되어 호출 되는 문제가 발생합니다.

    Prototype은 매번 새로운 instance를 생성해야하는데 그것이 불가능해진다는 겁니다.

     

    이건 조금 억지로 예시를 찾아보면

    오늘 밖에서 날아가는 비둘기를 잡아서 새장에 가뒀다고 가정해봅시다.

    새장에 가둔 행위가 Singleton이 되고, 새의 종류를 Prototype으로 생각하시면 되겠습니다.

    Singleton 내부에 Prototype을 둔다는 것은,

    비둘기를 가둬두고 내일이 되면 앵무새(?)로 변하길 바란다(?)라는 이야기가 되는건데..

    -> ? 그럴리가 없죠. 즉, Prototype이 변하지 않는 문제가 발생합니다.

    (현실에선 정상적인 경우지만, Spring에선 Prototype의 instance가 고정되니 문제라 볼 수 있습니다.)

     

    일단 예시도 개판(?)이긴 한데, 글 내용도 논리적으로 좀 이상하네요.

    (뭔가 답정너 느낌... 하하, 물론 코드 자체가 잘못되었다는 뜻은 아닙니다.)

     

    아무튼 Singleton 내 Prototype 구조의 의도는 정확하게 이야기하자면 아래와 같습니다.

    새장(Singleton)에 가둠으로써 새의 종류(Prototye)가 고정됐는데, 내가 아무짓을 안해도 다른 새로 변하길 바란다. 켘

     

     

    실 생활에선 이러한일은 해결 불가능하지만, Spring에선 해결책을 제공해줍니다.

    바로 Proxy class입니다.

    Proxy class: 다른 무언가와 이어지도록 하는 interface 역할.

     

    과정

    1. Singleton 내의 Prototype bean을 proxy로 감쌉니다.

    2. Singleton에서 Prototype을 호출 할 때 매번 proxy를 통해 참조합니다.

    3. proxy를 통해 참조하기 때문에 Prototype은 매번 새로운 instance를 제공합니다.

     

    Proxy class 설정하기

    @Component
    @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class A {
        ....
    }

    -> java dyanmic proxy는 interface에만 사용 가능하므로 class로 타겟 설정을 해줍니다.

    이렇게만 하면 조금 아쉬운데요. proxy class 관련한 내용도 추후 포스팅으로 찾아봽도록 하겠습니다.

     

     


    [정리]

    Singleton/Prototype

     

    Singleton은 이렇게 변화가 적고 참조가 많은 객체에 적합합니다.

    또한 Bean cache에 저장되어 인스턴스 호출에 성능 향상을 도와주죠.

    Prototype은 변화가 많은 객체에서 사용됩니다.

    동기화 비용이 객체 생성비용보다 크다면 Prototype으로 설정해 사용하는 것도 좋겠습니다.

    아! 추가적인 scope는 Spring docs에 나와있으니 해당 링크에서 참고하시면 될 것 같습니다.

    (이름을 보니 MVC 패턴에서 주로 쓰이는 것 같네요?, 뭐.. 잘 모르겠습니다)

     

     

     

     

     

    참고 자료

    Inflearn 백기선님 강의 영상

    Spring Docs - bean scope

    반응형

    'Back-end Developer > Server, Spring' 카테고리의 다른 글

    REST API (1)  (0) 2020.07.17
    AOP  (0) 2020.06.29
    POJO  (0) 2020.06.28
    Proxy (bean scope)  (0) 2020.06.24
    Bean  (0) 2020.06.22

    댓글

Designed by minchoba.