김원경 11월 23일, 2021에 포스트됨 공유하기 11월 23일, 2021에 포스트됨 델파이 2009이후의 Com을 사용하지 않는 DataSnap 확장성의 핵심은 서버 메서드 인스턴스 수명 주기(Life Cycle) 관리이다. DataSnap 아키텍처에서 클라이언트는 서버 메소드 클래스의 Public 메소드를 원격으로 호출한다. 개발자는 서버 메소드 클래스 인스턴스를 생성하고 파괴하는 것에 대해 걱정할 필요가 없다. 서버 클래스의 유형과 해당 수명 주기만 알려주면 된다. 서버 메소트의 수면 주기는 아래와 같은 3가지 옵션이 있다. Session 디폴트 옵션으로 즉, 연결된 모든 클라이언트에 대해 클라이언트가 연결할 때 생성되고 연결이 끊길 때 소멸되는 하나의 전용 서버 메서드 인스턴스가 있음을 의미한다. 이것은 "상태 저장" EJB(Enterprise Java Bean)의 개념과 매우 유사하다. Server 이 경우 모든 클라이언트는 동일한 서버 클래스 인스턴스의 메서드를 호출한다. 해당 메소드는 여러 스레드에서 동시에 호출될 수 있다 Invocation 이것은 아마도 가장 확장 가능한 가능성일 것입니다. 왜냐하면 서버 메소드 클래스 인스턴스는 메소드 호출 기간 동안만 생성되기 때문이다. 요청이 도착하기 직전에 인스턴스화 되고 호출이 완료되면 소멸된다. 이것은 "상태 비 저장" EJB와 개념적으로 매우 유사하다. 즉 서버의 비지니스로직(메소드) 호출시 어떤 LifeCycle을 사용하는지에 따라 성능이 달라질 수도 있을것이다. 예를들어 조회만 하는 메소드라면 어떤 옵션을 사용하시겠습니까 ? 서버 프로젝트 생성 File > New > Other 메뉴를 클릭하고 DataSnap 범주에서 DataSnap Server를 두 번 클릭하여 DataSnap 서버 애플리케이션을 생성한다. 2. 아래 화면과 같이 옵션을 선택하면서 Next를 누르면서 진행한다. 3. Form Application 선택->VCL Application 선택한다. 4. 아래와 같이 Server Methods Class는 선택하고 Sample Methods는 선택하지 않는다. 5. 포트를 테스트하고 아래와 같이 TComponent를 선택하고 Finish 버튼을 클릭한다. 6. 폼 이름, 유니트 이름, 프로젝트 이름을 각각 Form_Main(Main_Server.pas), LifeCycle_Server.dpr로 저장한다. 7. 데모를 위해 서버 메소드 클래스에 고유 식별자를 반환하는 GetId 메소드를 추가한다. 이러한 방식으로 클라이언트 프로그램은 통신하는 서버 내 부의 서버 메서드 클래스 인스턴스를 확인할 수 있다. 8. GUID(Globally Unique Identifiers)를 생성하는 기본 OS 기능을 호출하는 전역 기능을 제공하는 유니트를 생성하기 위해 File > New > New Unit를 선택하고 유니트 이름을 "GUID_utils"로 저장하고 아래와 같이 코드를 구현한다. unit GUID_utils; interface function GetNewGUID: string; implementation uses ActiveX, SysUtils; function GetNewGUID: string; var aGUID: TGUID; begin CoCreateGUID(aGUID); Result := GUIDToString(aGUID); end; end. 7. 기존의 TServerMethods1 클래스 안에 다음과 같이 코드를 구현한다. unit ServerMethodsUnit1; interface uses SysUtils, Classes, DSServer; type {$METHODINFO ON} TServerMethods1 = class(TComponent) private FID: string; public constructor Create(AOwner: TComponent); override; function GetID: string; end; {$METHODINFO OFF} implementation uses GUID_utils; { TServerMethods1 } constructor TServerMethods1.Create(AOwner: TComponent); begin inherited; FID := GetNewGUID; end; function TServerMethods1.GetID: string; begin Result := FID; end; end. 그렇다면 DataSnap은 TServerMethods1 클래스가 서버 메소드이고 공개 메소드가 클라이언트에 어떻게 노출될까? 이것은 주요 TDSServer 컴포넌트와 모든 서버 메서드 클래스 간의 링크 역할을 하는 TDSServerClass 컴포넌트의 역할입니다. 하나의 DataSnap 서버 애플리케이션에는 심장의 역활을 하는 항상 하나의 TDSServer 컴포넌트와 TDSServer가 클라이언트와 통신하는 여러 전송 콤포넌트, 프로그래머가 값을 할당할 수 있는 OnGetClass 이벤트를 제공하는 많은 TDSServerClass 컴포넌트가 있다. 클라이언트 요청이 도착할 때 인스턴스화해야 하는 서버 메소드 클래스의 유형입니다. OnGetClass 이벤트 구현에서 수행해야 할 가장 중요한 부분은 프로그래머가 매개변수에 대한 인스턴스 참조가 아니라 유형 참조를 할당한다는 사실이다. DataSnap 아키텍처에서 프로그래머는 서버 클래스의 수명 주기를 직접 제어하지 않는다. 선언적으로 수명을 관리하는 TDSServerClass 컴포넌트의 Lifecycle 속성이 있다. DSServerClass1.LifeCycle 속성의 기본값은 Session이다. 9. 서버 어플리케이선을 실행한다. 클라이언트 어플리케이션 작성 1. 새로운 VCL Forms Application을 생성하고 Form_Client(main_Client.pas), LifeCycle_Client.dpr로 저장한다. 2. 아래와 같이 화면을 설계한다. (TButton, TLabel 컴포넌트 추가) 3. 폼에 TSQLConnection 컴포넌트를 추가한다. Delphi 2009에서 DataSnap 서버에 대한 연결은 RDBMS 서버가 아닌 DataSnap 서버에 대한 연결을 제공하는 DBX4 드라이버의 형태로 구현되었있다. 클라이언트 관점에서 DataSnap 서버 인스턴스는 데이터베이스 인스턴스와 매우 유사하게 보이며 서버 메소드는 저장 프로시저와 매우 유사하다. 4. 아래의 속성을 다음과 같이 설정한다. Driver : DataSnap LoginPrompt : False Connected : True 5. SQLConnection1 컴포넌트를 마우스 오른쪽 버튼으로 클릭하고 컨텍스트 메뉴에서 "Generate DataSnpa Client Classes"을 선택한다. 6. 클라이언트 프로그램에서 서버 메서드를 호출하려면 Client가 추가된 서버 클래스와 이름이 같은 생성된 클라이언트 클래스를 인스턴스화해야 한다. 7. 생성된 유니트 이름을 Proxcy.pas로 저장하고 화면에서 uses절에 추가한다. 8. GetId 메소드를 호출하고 레이블 컴포넌트에 수신된 값을 표시하기 위해 OnClick 이벤트를 다음과 같이 구현한다. procedure TForm_Server.Button1Click(Sender: TObject); var aClient: TServerMethods1Client; begin aClient := TServerMethods1Client.Create(SQLConnection1.DBXConnection); try Label1.Caption := aClient.GetID; finally aClient.Free; end; end; 9. 프로그램을 실행하여 버튼을 클릭하면 원격 DataSnap 서버 애플리케이션 내에서 실행되는 서버 메소드 클래스 인스턴스의 고유한 전역 식별자가 표시 된다. 버튼을 더 많이 클릭하면 식별자가 변경되지 않는 것을 볼 수 있다. 윈도우 탬색기에서 클라이언트 응용 프로그램을 또 실행하면 다른 인스턴스를 시작한다. 버튼을 클릭하면 식별자가 다른 것을 볼 수 있다. 이는 두 클라이언트 응용 프로그램이 동일한 서버 클래스의 다른 인스턴스와 통신하고 있음을 의미한다. Server 및 Invocation 당 수명 주기 테스트 TDSServerClass.LifeCycle 속성에 대해 다른 값들을 지정하여 테스트 해보자. 서버에 두 개의 TDSServerClass 컴포넌트를 더 추가하고 LifeCycle 속성을 각 각 다르게 지정하 세 개의 서버 메소드 클래스가 필요하다. 1. 모든 클라이언트 프로그램과 서버 프로그램을 닫는다. 2. 서버 프로그램을 오픈하고 DSServerClass1 컴포넌트를 선택하고 Name 속성을 "DSServerClass_Session"으로 변경한다. 3. TDSServerClass 컴포넌트를 두 개 더 추가하고 각 각의 Name을 "DSServerClass_Server" , "DSServerClass_Invocation"으로 변경한다. 4. Lifecycle 속성도 각 각 Server, Session으로 변경한다. 5. 서버 메소드 클래스 유니트로 이동하여 "ServerMethodsUnitSession"으로 저장하고 서버 클래스 이름을 "TServerMethodsSession"으로 변경하나다. 6. 위의 소스를 복사한다. 7. 새로운 unit를 추가하고 "ServerMethodsUnitServer"로 저장하고 유니트에 6의 복사된 내용을 붙이기한다. 8. 클래스 이름을 TServerMethodsServer"로 변경한다. 9. 같은 방법으로 "ServerMethodsUnitInvocation.pas", "TServerMethodsInvocation"으로 변경한다. 10. 마지막 작업은 3개의 DSServerClass 컴포넌트에 대해 아래와 같이 OnGetClass 이벤트를 구현한다. implementation {$R *.dfm} uses ServerMethodsUnitSession, ServerMethodsUnitServer, ServerMethodsUnitinvocation; procedure TServerContainer1.DSServerClass_InvocationGetClass( DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); begin PersistentClass := TServerMethodsInvocation; end; procedure TServerContainer1.DSServerClass_ServerGetClass( DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); begin PersistentClass := TServerMethodsServer; end; procedure TServerContainer1.DSServerClass_sessionGetClass( DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); begin PersistentClass := TServerMethodsSession; end; end. 11. 이제 서버가 준비되었다. 서버를 실행한다. 12. 클라이언트 프로젝트로 전환하여."SQLConnection1 컴포넌트의 Connected 속성을 false로 설정한 다음 다시 true로 설정하여 최신 버전의 서버에 연결되어 있는지 확인한다. 13. SQLConnection1 컴포넌트를 마우스 오른쪽 버튼으로 클릭하고 컨텍스트 메뉴에서 Generate DataSnap Client Class"을 선택하여 프록시 소스 코드를 재생성한다. 모든 서버 메소드 클래스에 대해 생성된 해당 클라이언트 클래스가 있으므로 이제 클라이언트 클래스3개가 있는것을 확인 할 수 있다. 14. 클라이언트 폼에 두 개의 버튼와 두 개의 레이블을 추가하고 아래와 같이 코드를 추가한다. procedure TForm_Client.Button1Click(Sender: TObject); var aClient: TServerMethodsServerClient; begin aClient := TServerMethodsServerClient.Create( SQLConnection1.DBXConnection); try Label1.Caption := aClient.GetID; finally aClient.Free; end; end; procedure TForm_Client.Button2Click(Sender: TObject); var aClient: TServerMethodsSessionClient; begin aClient := TServerMethodsSessionClient.Create( SQLConnection1.DBXConnection); try Label2.Caption := aClient.GetID; finally aClient.Free; end; end; procedure TForm_Client.Button3Click(Sender: TObject); var aClient: TServerMethodsInvocationClient; begin aClient := TServerMethodsInvocationClient.Create( SQLConnection1.DBXConnection); try Label3.Caption := aClient.GetID; finally aClient.Free; end; end; 15. 두개의 프로그램을 실행하면 두 클라이언트 모두 변경되지 않는 동일한 "서버 수명 주기" 인스턴스에 연결된다. 클라이언트마다 세션 인스턴스가 다르며 변경되지 않는다. "호출" 버튼을 클릭할 때마다 다른 식별자가 표시된다. 이는 요청을 처리하는 다른 서버 메소드 클래스 인스턴스가 항상 있음을 의미한다. 샘플 소스 : datasnp_lifecycle.zip 인용하기 이 댓글 링크 다른 사이트에 공유하기 더 많은 공유 선택 사항
Recommended Posts
이 토의에 참여하세요
지금 바로 의견을 남길 수 있습니다. 그리고 나서 가입해도 됩니다. 이미 회원이라면, 지금 로그인하고 본인 계정으로 의견을 남기세요.