SSISO Community

갤러리정

AOP를 향하여, 닷넷 프록시 - 3

AOP를 향하여, 닷넷 프록시 - 3
  저 자 : 유경상
  출판일 : 2003년 7월호

  메쏘드 호출 메시지
앞 서 TP가 메쏘드 호출을 메시지로 바꾸어 준다는 얘기를 하였다. 그렇다면 이 메시지는 어떠한 정보를 갖고 있는 것일까? TP에 의해 메시지화된 메쏘드 호출 정보는 IMessage 인터페이스를 구현하는 객체로서 메시지 객체로 불린다. 메시지 객체들은 System. Runtime.Remoting.Messaing 네임스페이스에 정의되어 있지만 대부분 internal로 선언되어 있어 프로그래머가 직접 이들의 인스턴스를 생성하거나 메쏘드, 프로퍼티를 접근할 수 없도록 되어 있다. 대신 표준 인터페이스로서 IMessage를 통해 접근이 가능하다.

메시지 인터페이스
메쏘드 호출 메시지는 메쏘드 종류와 메쏘드 호출/결과에 따라 몇 가지로 분류될 수 있다. 닷넷 프레임워크는 이러한 분류에 따라 IMessage에서 파생된 인터페이스들을 정의하고 있다(<그림 1>). IMessage 인터페이스는 프록시 뿐만 아니라 다양한 용도로도 사용되는 인터페이스이다. 따라서 메쏘드 호출에 관련된 인터페이스로서 IMethodMessage 인터페이스가 존재한다. 이 인터페이스는 단순한 컬렉션만 달랑 하나 제공하는 IMessage 인터페이스와는 달리 메쏘드의 매개변수, 메쏘드 메타 데이터 등
을 액세스할 수 있는 다양한 메쏘드와 프로퍼티를 제공한다.



IMethodMessage를 다시 메쏘드 호출에 사용되는 메시지와 메쏘드 반환에 사용되는 메시지로 구분해 놓은 것이 IMethodCallMessa ge와 IMethodReturnMessage 인터페이스이다. IMethodCall Message는 IMethodMessage와 다르게 입력 매개변수([in] 매개변수 및 [ref] 매개변수)에 접근할 수 있는 별도의 프로퍼티/메쏘드를 제공하며, IMethodReturnMessage 메시지는 결과 값([ref] 매개변수, [out] 매개변수 그리고 리턴 값)을 액세스할 수 있는 별도의 프로퍼티/메쏘드를 제공한다.

특히 IMethodReturnMessage는 메쏘드에서 발생할 수 있는 예외를 설정할 수 있는 프로퍼티 역시 제공한다. 메쏘드 호출과 약간 구분되어 특별한 처리가 필요한 것이 생성자 호출이다. 생성자는 객체 생성과 더불어 프레임워크에 의해 자동으로 호출되는 특수한 ‘메쏘드’이기 때문에 별도의 IConstructionCall Message 및 IConstructionReturnMessage 인터페이스를 통해 액세스할 수 있다.

이들 여러 인터페이스에서 항상 염두에 둘 것은 이들은 모두 IMessage 인터페이스에서 파생되었다는 점이며, 파생 인터페이스에서 접근 가능한 모든 정보는 IMessage 인터페이스를 통해서도 접근 가능하다는 점이다. 대부분의 메시지 객체는 이들 인터페이스를 통해서만 접근이 가능하지만 몇몇 메시지 객체는 직접 생성이 가능하기도 하다. 그것이 바로 ReturnMessage 객체이며 이 클래스는 특이하게도 public으로 선언되어 있다. 따라서 프록시에서 실제 호출될 메시지를 호출하지 않고 이 메시지를 직접 생성하여 반환함으로서 마치 메쏘드가 호출된 것처럼 흉내 낼 수도 있다. 실제 예제는 조금 후에 살펴보기로 하자.

지면 관계상 이들 인터페이스가 어떤 메쏘드/프로퍼티들을 가지고 있으며 구체적으로 어떻게 사용한다는 내용을 모두 설명할 수 없음을 독자들은 이해해 주기 바란다. 예제 코드를 다루면서 몇몇 메쏘드와 프로퍼티는 사용법을 다루겠지만 나머지에 대한 상세한 내용은 MSDN 라이브러리나 참고자료를 살펴보기 바란다.

메시지 전달
지금까지 우리는 메쏘드 호출이 발생하면 TP가 스택 프레임을 통해 메쏘드 호출을 메시지 형태로 변환한다는 것을 알았으며 이 메시지를 어떤 인터페이스를 통해 액세스할 수 있는가도 알아봤다. 이제 남은 것은 메시지 형태의 메쏘드 호출을 어떻게 실제 메쏘드 호출에 사용하는가를 살펴볼 차례이다. 요는 메시지 형태의 메쏘드 호출을 다시 스택 프레임 형태로 바꾸고 실제 메쏘드로 제어를 옮기는 일이다.

스택 프레임을 메시지로 바꾸는 것과 비슷하게 메시지를 스택 프레임으로 바꾸는 일 또한 매우 복잡하고 어려운 일이 될 것임은 너무도 자명하다. 닷넷 프레임워크는 정확하게 이 일을 수행하는 클래스를 제공한다. StackBuilderSink 클래스가 바로 이 일을 수행해 준다. 하지만 이 클래스 역시 internal로 선언되어 있기 때문에 직접적인 액세스가 불가능하다. 다만 RemotingServices 클래스의 ExecuteMessage 메쏘드를 통해 간접적으로 StackBuilderSink를 통해 메쏘드 호출을 수행할 수 있다.

public class RemotingServices {
public static IMessage ExecuteMessage(
MarshalByRefObject target,
IMethodCallMessage msg);
}

ExecuteMessage 메쏘드는 메쏘드 호출을 수행할 클래스 인스턴스와 메쏘드 호출 메시지를 매개변수로 하여 StackBuilderSink의 인스턴스를 생성하고 메쏘드를 디스패치한다. StackBuilderSink 객체는 스택 프레임을 생성하여 메쏘드 호출을 수행하고, 더 중요한 일로서 메쏘드 호출의 결과를 다시 메시지화하여 반환하여 준다. 비록 ExecuteMessage 메쏘드가 IMessage 인터페이스를 반환하지만 이 인터페이스는 IMethodReturnMessage 혹은IConstructionReturn Message일 가능성이 매우 높다.

메시지를 스택 프레임으로 바꾸는 것은 StackBuilderSink만은 아니다. TP 역시 동일한 작업을 수행한다. 메쏘드 호출이 끝나고 결과를 호출자(caller)에게 반환할 때를 생각해 보자. 메쏘드 호출 결과는 아직 메시지 형태로만 존재할 뿐이다. 따라서 이 메쏘드 호출 결과를 다시 스택 프레임으로 변환할 필요가 있다. 이 일은 TP에 의해 수행되므로 호출자는 프록시가 사용되고 있다는 것을 알지 못할 것이다.

정리
자, 이제까지 설명한 내용을 정리해 보자. 호출자가 프록시가 사용되는 객체의 메쏘드를 호출하면 TP가 그 호출을 가로챈다. 그리고 스택 프레임 형태의 메쏘드 호출 정보를 메시지 객체로 전환한다. 이제 TP는 메시지를 매개변수로 하여 RP의 Invoke 메쏘드를 호출하게 된다. RP는 필요한 전처리를 수행하고 이 메시지를 Remoting Services.ExecuteMessage 메쏘드를 통해 StackBuilder Sink에게 전달하게 된다.

StackBuilderSink는 메시지를 다시 스택 프레임으로 전환하고 실제 메쏘드 호출을 수행하게 될 것이다. 메쏘드 호출이 종료되면 StackBuilderSink는 메쏘드 호출 결과를 다시 메시지 형태로 변환하고 이것을 RP에게 반환한다. 메쏘드 호출이 종료되었으므로 RP는 필요한 후처리를 수행할 수 있다. 후처리 수행 후 RP는 다시 메쏘드 호출 결과 메시지를 TP에게 반환하며 TP는 메쏘드 호출 결과를 스택 프레임에 반영하여 호출자에게 반환한다. 이 과정을 <그림 2>에 보인다. 반드시 이러한 과정을 거치지는 않지만 이제 곧 구현해 볼 우리의 커스텀 프록시는 이와 같은 과정을 거치게 된다. 이번 컬럼에서는 다루지 않지만 ContextBoundObject 클래스와 메시지 싱크(message sink)를 사용하면 이보다 더 복잡한 과정을 거치게 될 것이다.

876 view

4.0 stars