ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Proxy (bean scope)
    Back-end Developer/Server, Spring 2020. 6. 24. 18:55

    사실 이 글을 쓸지 말지 고민을 많이 했습니다.

    뭔가 Spring만의 개념만 쓰기엔 아직 필요한 부분 외에는 공부가 덜 된 느낌이라..ㅎㅎ

    (지속해서 공부하며 추가하겠습니다.)

     

    Proxy

    우선 Spring에서 Proxy가 어떻게 쓰이는지 알기 위해선, 일반적으로 Proxy가 무엇인지 알면 좋겠죠.

    연관해서 이해가 가능할 수 있으니까요.

    사전적 정의부터 알아보겠습니다.

    Proxy [ ˈprɑːksi ] 
    1. 대리(권)
    2. 대리인
    3. (측정·계산하려는 다른 것을 대표하도록 이용하는) 대용물

    (출처: naver 사전)

     

    단어의 의미를 보니.. 어느 정도 역할이 유추가 됩니다.

    뭐.. 술자리에서 볼 수 있는 흑기사? 같은 느낌도 있구요. ㅎㅎ

    대신 무언가 처리해 주는? 이러한 애들의 이름 앞에 'proxy ~ 어쩌고'라고 붙이는 것 같네요.

     

     

    우리 컴공인들에게 가장 친근한 것은 proxy server죠.

    Proxy server의 뜻은 wiki에서 찾을 수 있었습니다.

    프록시 서버 (영어: proxy server 프록시 서버[*])는 클라이언트가 자신을 통해서 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해 주는 컴퓨터 시스템이나 응용 프로그램을 가리킨다. 서버와 클라이언트 사이에 중계기로써 대리로 통신을 수행하는 것을 가리켜 '프록시', 그 중계 기능을 하는 것을 프록시 서버라고 부른다.

    서버와 클라이언트 사이에서 중계기 역할을 하며 대리로 통신을 수행하는 것.

    이렇게 보니 공통점이 보입니다. 중간에서 연계 역할, 실 생활에서는 중개사님들의 역할을 한다고 볼 수 있겠네요.

     

     

    그럼 중간에서 어떤 역할을 하기에 proxy를 사용하게 되는 것일까요?

    • proxy server에서는 cache에 client 쪽에서 요청되었던 내용들을 저장해 둡니다.
    • 이후 같은 요청이 들어오면 cache에서 해당 요청에 대한 응답을 건네줍니다.
    • 결국 원격 서버로 굳이 접속해 데이터를 전달해주지 않아도 되니 속도 측면에서 상당한 이익이 있습니다.
    • 속도도 빠르고 몇몇의 요청은 proxy server에서 바로바로 처리되니 병목 현상도 방지할 수 있다고 합니다.

     

    대략적인 감은 잡았으니 Spring의 proxy class에 대해 알아보겠습니다.

    Spring에서 proxy 또한 중간에서 어떤 역할을 해 줄 것으로 보입니다.

    우선 지난번 문제를 다시 가져와보죠.

     

    Bean scope는 대표적으로 두 가지가 있는데 바로 singleton/prototype 입니다.

    singleton은 Application 전반에 걸쳐 해당 클래스에 대한 인스턴스가 하나만 생성된다는 특징이 있고

    prototype은 필요시 매번 인스턴스를 새로 생성해 제공한다는 특징을 가졌습니다.

     

    singleton 내에 prototype bean이 존재하는 경우

    singleton은 한 번만 생성되어 고정되고 요청마다 같은 bean의 인스턴스를 던져줍니다.

    하지만 prototype은 매번 새로운 인스턴스가 필요한데, singleton에 의해 이 또한 고정되는 것이 문제였습니다.

    이를 proxy class를 통해 해결해 줄 수 있다는 것이 저번 포스팅까지의 내용이었습니다.

     

    Spring proxy

    원래 객체를 proxy로 감싸고, client 측의 요청을 감싸진 proxy class를 통해 대리로 처리하도록 유도

    사용 목적

    접근을 제어가 필요하거나, 부가 기능을 추가하고 할 때.

     

    우리가 proxy를 적용하는 목적은 singleton이 prototype의 직접 참조를 막기 위함입니다.

    prototype 인스턴스의 지속적인 변경을 도울 수 있는 proxy로 감싸도록 해서 정상적인 동작을 유도합니다.

     

    이러한 동작이 어떻게 이루어지는지 좀 더 자세히 알아보겠습니다.

     

    아래는 Spring docs(Scoped beans as dependencies)에서 설명하는 내용입니다.

    The Spring IoC container manages not only the instantiation of your objects (beans), but also the wiring up of collaborators (or dependencies). If you want to inject (for example) an HTTP request-scoped bean into another bean of a longer-lived scope, you may choose to inject an AOP proxy in place of the scoped bean. That is, you need to inject a proxy object that exposes the same public interface as the scoped object but that can also retrieve the real target object from the relevant scope (such as an HTTP request) and delegate method calls onto the real object.

    IoC conatiner는 객체(bean)의 인스턴스화를 관리해줄 뿐만 아니라 collaborators (또는 dependencies)의 연결성도 도와줍니다. 만약 HTTP request-scoped bean을 scope 주기가 더 긴 bean에 주입하려 한다면, scoped bean을 AOP proxy로 대체하여 사용할 수 있습니다. 즉, public interface를 노출시키는 proxy 객체를 scoped object를 대신해 사용 가능할 뿐만 아니라, 해당 scope에 대한 실제 타겟 객체를 받을 수 있고 실제 객체로부터 위임받아 메소드 호출도 가능합니다.

     

    너무 멋대로 의역한 감이 없지 않은데...(컼;;)

    Collaborator는 말 그대로 타겟 객체와 함께 사용되는 것들로 해석하시면 될 것 같습니다.

    결론적으로 proxy를 사용해도 실제 객체에 대한 정보를 그대로 가져다 쓸 수 있다고 써있네요.

     

     

    docs에서도 저희가 고민하는 동일한 문제에 대해 다루고 있어 가져왔습니다.

    userMananger(singleton) > userPreferences(session) ====> scope 주기

    <bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
    
    <bean id="userManager" class="com.something.UserManager">
        <property name="userPreferences" ref="userPreferences"/>
    </bean>

    -> 동일하게 scope가 긴 singleton에서 상대적으로 짧은 session을 호출합니다.

     

    proxy를 생성하고, proxy를 통해 실제 객체를 가져오는 동작은 아래와 같습니다.

    1. The container creates an object that exposes the exact same public interface as the UserPreferences class (ideally an object that is a UserPreferences instance), which can fetch the real UserPreferences object from the scoping mechanism (HTTP request, Session, and so forth).

    2. The container injects this proxy object into the userManager bean, which is unaware that this UserPreferences reference is a proxy.

    3. In this example, when a UserManager instance invokes a method on the dependency-injected UserPreferences object, it is actually invoking a method on the proxy.

    4. The proxy then fetches the real UserPreferences object from (in this case) the HTTP Session and delegates the method invocation onto the retrieved real UserPreferences object.
    1. container는 UserPreferences 클래스와 완전히 동일한 public 인터페이스 노출시키는 객체를 생성하고, 해당 객체는 실제 UserPreferences 객체를 scoping mechanism을 통해 가져다 줍니다.
    2. 컨테이너는 해당 프록시 객체를 userManager bean에 주입시키며, 주입 받는 bean에서는 UserPreferences reference가 프록시인지 알아채지 못합니다. (즉, 실제 타겟 객체로 인식한다 생각하시면 됩니다)
    3. 이러한 경우 UserManager 인스턴스가 의존성이 주입된 Userpreferences 객체의 메소드를 호출하면, 실제로는 프록시에서 메소드가 호출됩니다.
    4. 호출된 후 프록시는 실제 UserPreferences 객체로부터 http session을 가져오고 메소드 호출 권한을 위임 받아 가져옵니다.

    결론적으로 prototype(session) 인스턴스는 지속적으로 생성되고 이를 singleton에서 proxy를 통해 참조해 의도대로 생성이 가능합니다.

    또한, 대표적으로 proxy를 생성해 설정하는 방법은 두가지가 있습니다.

    • CGlib을 사용한 dynamic proxy 설정: class도 가능 (3rd part, public만 가능)
    • jdk dynamic proxy: interface 전용

     

    이렇게 지난번 문제를 해결할 수 있었습니다.

    dynamic proxy, CGlib 등 관련 내용도 같이 쓰면 좋겠지만..

    너무 많은 이야기가 한데 섞여있는 느낌이고, 아직은 제 지식도 부족한 관계로 이후 추가하도록 하겠습니다.

    (아마도 AOP관련 이야기를 먼저 하는게 좋을 것 같아요.)

     

     

    잘못된 내용이나, 이해가 잘 안되는 부분은 댓글로 알려주시면 늦지않게 답변 드리겠습니다. 감사합니다.

    반응형

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

    REST API (1)  (0) 2020.07.17
    AOP  (0) 2020.06.29
    POJO  (0) 2020.06.28
    Bean 그리고 scope  (0) 2020.06.23
    Bean  (0) 2020.06.22

    댓글

Designed by minchoba.