Flex 모듈 프로그래밍의 기초 - Application domain의 이해 1부
1. Application domain에 대해
1.1 모듈화와 모듈화에 따른 application domain의 역할
프로젝트를 하다 보면 모듈화를 할 필요가 생긴다. 모듈화는 하나의 메인 응용 프로그램에 모든 기능이 있는 대신, 관련된 기능을 떼어내어 모듈을 만들어 필요한 시점에 동적으로 불러 사용할 수 있도록 만드는 것을 의미한다.
가령 Flex로 만든 블로그가 있다고 가정하면. 블로그에는 글쓰기, 리스트, 방명록, 관리, 메뉴 등이 존재할 것이다. 이러한 것이 하나의 SWF 파일에 모두 존재한다면 보여주지도 않을 방명록, 관리 부분까지 처음 프로그램 실행부터 전부 불러와야 하는 부담이 생긴다. 그래서 필요에 따라 동적으로 읽어서 사용할 수 있도록 글쓰기에 관련된 SWF, 리스트에 관련된 SWF 등으로 나눠서 만들어 놓으면 필요할 때 사용할 수 있으므로 더욱 효율적일 것이다.
이렇게 모듈화를 할 경우 블로그 메인 프로그램과 각 글쓰기 모듈 프로그램, 리스트 모듈 프로그램, 방명록 모듈 프로그램간에 통신을 하게 될 것이고, 때에 따라서는 메인 프로그램에서 정의한 자원을 모듈에 포함할 것 없이 재사용할 필요도 있을 것이다. 이렇게 하면 모듈에 메인 프로그램과 동일한 중복 코드를 가지고 있을 필요가 없어 용량이 줄어들 수 있기 때문이다. 그렇게 되면 자연스럽게 메인-모듈, 모듈-모듈간에 자원을 공유하는 일이 발생하게 된다.
이 문서는 모듈화를 하는 방법을 제시해준다기 보다는 모듈화를 위해 선행적으로 알아야 할 한가지를 언급하고자 한다. 그 중 하나가 바로 여기서 지금부터 다룰 application domain(응용 프로그램 영역)이다. application domain은 서로 다른 SWF 프로그램끼리 자원 공유를 위한 영역을 구분 지을 수 있도록 도와준다.
Namespace와의 비교
application domain에 대해서 이해하기 위해 Namespace와 비교해 보도록 하겠다.
Namespace는 이름, 용어 혹은 단어 항목들을 위한 문맥(context)을 제공하는 추상적인 컨테이너(container)라고 정의되어 있다. Namespace는 Java나 Flex, ActionScript3에서 사용하는 패키지(Package)와 거의 동일하다. Namespace는 프로그램 안에 같은 이름의 Class가 있을 때 구분해주는 역할을 한다. 가령 com.jidolstar.URLUtil과 flash.jidolstar.URLUtil 이 있다면 URLUtil로 이름은 같지만 Namespace는 다르므로 이 클래스는 이름만 같지 전혀 다른 클래스이다. 이렇듯 Namespace를 잘 활용하면 같은 이름의 클래스로 다른 동작을 하도록 만들 수 있고 또는 프로젝트 진행시 클래스 명이 충돌하는 경우도 방지할 수 있다.
그럼 application domain의 경우는 어떨까? Namespace는 단일 응용 프로그램에 같은 이름의 Class를 구분하기 위해 사용되는 반면 application domain은 여러 개의 응용 프로그램간에 같은 이름의 Class를 구분하기 위해 사용된다.
프로그램들이 하나의 application domain안에 포함되어 있다면 같은 이름을 가진 Class는 단 한 개만 존재가 가능하다. 가령 부모 프로그램의 Class 정의만 남고 자식 프로그램의 Class는 무시된다. 반면 프로그램들의 application domain이 서로 다르다면 같은 이름을 가진 Class라 할지라도 이들 Class는 서로 다른 application domain에 존재하는 것이므로 다른 것으로 해석된다.
1.2 Application domain 개념
아래는 application domain에 대해서 간단히 설명하고 있다.
application domain은 Loader의 load() 또는 loadBytes() 메쏘드를 이용해 ActionScript3.0으로 만들어진 SWF 파일을 불러들일 때만 사용된다.
application domain를 적용하기 위해 ApplicationDomain 클래스를 LoaderContext 클래스의 applicationDomain 속성에 대입하여 Loader의 load() 및 loadBytes() 메쏘드를 호출시 인자로 LoaderContext의 인스턴스를 넘겨주면 된다.
application domain은 동일한 보안 도메인(security domain)안에서 하나 이상의 SWF 파일 안에 제작된 ActionScript3.0 코드들을 목록화하여 관리한다. 다시 말하면 하나의 application domain안에서 여러 개의 SWF 파일에서 작성한 ActionScript3.0 코드를 관리할 수 있다. 또한 서로 다른 SWF 파일간에 다른 application domian을 안에 있다면 SWF 파일에 작성된 ActionScript3.0 코드는 중복되어지지 않는다. ActionScript3.0 코드는 Class 형태로 제작되며 결과적으로 application domain을 이용해 SWF 파일에 정의된 Class들이 서로 같은 영역에서 정의될 수 있고 또는 다른 영역에서 정의될 수도 있다. 또한 부모 SWF 파일에서 자식 SWF 파일에만 Class 정의 사용할 수 있도록 허용할 수 있다.
위처럼 application domain은 SWF 프로그램에 ActionScript 3.0으로 제작된 Class 정의를 원하는 영역(도메인)에 나누는 역할을 한다. 어도비 라이브 독(Adobe Livedocs)에 의하면 application domain에 대해서 아래 중요한 사실을 언급하고 있다.
1. SWF 파일 안에 있는 모든 코드는 하나의 application domain 안에 존재되도록 정의된다. 메인 응용 프로그램(main application)의 application domain은 current domain이다. system domain current domain을 비롯하여 모든 application domain을 포함하기 때문에 모든 Flash Player 클래스를 가지고 있다.
2. system domain을 제외한 모든 application domain은 그와 연결된 parent domain을 가진다. 메인 응용 프로그램의 application domain에 대한 parent domain은 system domain이다. 같은 application domain안에서 부모 프로그램과 자식 프로그램이 있다고 가정하자. 이때 부모 프로그램이 불러들인 자식 프로그램 안에 클래스들은 그 부모 안에 같은 이름의 클래스가 정의되어 있지 않을 때만 정의되고 사용할 수 있다. 또한 자식 프로그램의 클래스가 부모의 있는 클래스를 재정의(override) 할 수 없다.
같은 보안 도메인(scrutiny domain) 안에서 LoaderContext의 Application Domain 속성에 자신이 사용하고자 하는 Application Domain 속성을 아래 4가지 중 하나를 선택하면 되겠다.
1. 부모의 application domain을 상속받은 application domain
이것이 기본값이다.
이 선택은 new ApplicationDomain(ApplicationDomain.currentDomain) 구문을 이용하는 것이다.
이 방식은 자식의 application domain에서 부모에서 정의한 Class를 직접 사용할 수 있다. 가령 자식에서 ApplicationDomain.currentDomain.getDefinition(“부모에서 정의된 클래스명”)로 접근이 가능하다는 것을 의미한다. 반면 부모는 자신의 application domain에서 자식에서 정의된 Class에 접근이 불가능하다.
이 방식의 장점은 자식에서 부모에 이미 정의된 Class와 이름이 같은 Class를 정의해도 오류가 나지 않는다. 자식은 해당 Class에 대한 부모의 정의를 상속받기만 하며, 부모와 충돌하는 클래스 정의는 무시된다.
2. 부모 자신의 application domain
ApplicationDomain.currentDomain 구문을 사용하는 것과 같다. 자식 SWF 파일을 불러오면 부모와 자식이 상대방에서 정의한 Class에 직접 접근이 가능하다. 서로 ApplicationDomain.currentDomain.getDefinition()을 이용해 접근이 가능하다. 단, 자식에서 부모와 같은 Class를 정의를 사용했다면 자식의 Class 정의는 무시된다.
3. 시스템 application domain을 상속받은 application domain
이는 new ApplicationDomain(null) 구문을 사용하는 것과 같다. 이렇게 하면 부모와 자식간에 정의된 Class는 서로 다른 application domain에 있기 때문에 자신의 application domain 안에서는 상대방에서 정의한 Class를 참고할 수 없게 된다. 부모와 자식간에 같은 이름의 Class가 있더라도 application domain이 다르므로 자식의 Class정의가 무시되는 경우는 없다.
4. 임의의 application domain을 상속받은 application domain
이 방법은 application domin 계층 구도가 복잡해질 수 있으므로 지양하는 방법이다. 자식 SWF을 자신의 security domain 안에 있는 임의의 application domain을 이용해 사용하는 것으로 가령, new ApplicationDomain(ApplicationDomain.currentDomain.parentDomain.parentDomain)을 사용하면 자식 SWF이 현재 application domain의 부모의 부모 domian을 상속받아 application domain을 만든다.
때때로 부모와 자식이 상대방의 application domain에 접근해야 하는 경우도 있다. 상대방이 application domain에 접근할 수 있는 경우 ApplicationDomain.currentDomain으로 상대방의 Class 정의를 가져올 수 있다. 또 다른 경우 부모가 자식 SWF를 로드가 완료했을 때, Loader 함수의 인스턴스가 loader라면 loader.contentLoaderInfo.applicationDomain.getDefinition()를 이용해서 자식의 application domian에 접근하여 자식에서 정의한 Class를 사용할 수 있다. 자식이 로드되는 방식을 알고 있는 경우 부모의 application domian에 접근할 수 있는데 기본적으로 ApplicationDomain.currentDomain.parentDomin을 이용하여 부모에서 정의한 Class에 접근이 가능하겠다.
2. ApplicationDomain Class 사용법에 따른 동작방식 해석
아래 <그림 1>은 단일 도메인(domain1.com)에 존재하는 다양한 SWF 프로그램(module1.swf, module3.swf, application2.swf)을 메인 SWF 프로그램(application1.swf)에서 Loader 클래스의 인스턴스를 통해 불러서 사용하는 모습을 묘사하고 있다. 이때 불러오는 SWF 프로그램들은 각자의 application domain에 등록되어 있다는 것을 알 수 있다.
<그림 1> Application domain과 SWF 프로그램 간의 관계
아래 예제는 [그림 1]의 Usage B의 경우와 같다.
|
package { import flash.display.Loader; import flash.display.Sprite; import flash.events.*; import flash.net.URLRequest; import flash.system.ApplicationDomain; import flash.system.LoaderContext; public class ApplicationDomainExample extends Sprite { private var ldr:Loader; public function ApplicationDomainExample() { ldr = new Loader(); var req:URLRequest = new URLRequest("Greeter.swf"); var ldrContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain); ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler); ldr.load(req, ldrContext); } private function completeHandler(event:Event):void { var ClassRef:Class = ApplicationDomain.currentDomain.getDefinition("Greeter") as Class; var myGreeter:* = new ClassRef(); var message:String = myGreeter.welcome("Tommy"); trace(message); // Hello, Tommy } } } |
간략하게 설명하면 메인 프로그램에서 모듈 SWF를 불러올 때 메인과 같은 application domain으로 설정한다. 메인 프로그램에 불러온 모듈 SWF 파일에 정의된 클래스(Greeter)의 정의를 이용해 인스턴스를 생성하고 클래스에 정의된 메쏘드에 접근하는 것을 확인할 수 있다.
이처럼 부모가 Loader 클래스를 이용해서 ActionScript 3.0으로 작성된 외부 SWF 파일을 자식으로 불러오고 있다. Loader 클래스의 context 속성에 LoaderContext 객체를 넘겨주는데 LoaderContext에 바로 applicationDomain 매개변수를 넣을 수 있다. 위 예제에서는 메인 프로그램의 application domain인 current domain을 매개변수로 넘겨주었다. 이는 불러들이는 SWF 파일에 동일한 application domain을 적용했다는 것을 의미한다. 자식을 부모의 application domain에 포함했기 때문에 자식에서 정의한 Greeter Class를 부모의 application domain 안에서 사용할 수 있게 된다.
위의 과정에 대해서 좀더 자세히 알아보자. <그림 1>에서 application domain 사용 예에 대해 1부터 3까지 있다는 것을 알 수 있다. 아래 <그림 2>는 application domain 안에서 어떻게 Class가 공유되는지 살펴보기 위한 것이다.
<그림 2> application domain을 지정하는 3가지 방법
<그림 2>에서 클래스 명에 X표는 로드 후 정의에서 무시되는 클래스라는 것만 일단 기억하자. 지금부터 <그림 2>에서 표현하고 있는 application domain의 3가지 사용법에 대해서 언급하고 그에 따른 동작방식에 대해 이해해 보겠다.
2.1 ApplicationDomain 사용법A – 새로운 application domain 사용
|
var loader:Loader = new Loader(); var request:URLRequest = new URLRequest("application2.swf"); var context:LoaderContext = new LoaderContext(); context.applicationDomain = new ApplicationDomain(); loader.load(request,context); |
위 코드는 메인 프로그램인 application2.swf 내에서 짜여진다. 이는 메인 SWF 프로그램과 전혀 다른 application domain 안에 존재하도록 만든다. 불러오는 컨텐츠의 이름이 module2.swf가 아닌 application2.swf로 표현한 이유는 서로 다른 application domain이기 때문이다. application2.swf의 parent domain은 system domain이 된다.
<그림 3> 완전히 다른 application domain으로 외부 SWF를 불러오는 경우
<그림 3>에서 application1.swf와 application2.swf가 완전히 다른 application domain이기 때문에 서로의 각자 영역에서 정의된 com1::Class1과 com2::Class2는 상대방의 프로그램에 의해 영향을 받지 않는다.
|
var ClassRef:Class = getDefinitionByName("com1.Class1") as Class; |
참고로 위에서 사용된 getDefinitionByName() 함수는 내부적으로 ApplicationDomain.currentDomain.getDefinition()을 호출하도록 만들어져 있다.
만약 application1.swf에서 위와 코드와 같이 접근하면 application2.swf를 불러온 상태에서도 application1.swf에 정의한 com1.Class1에 접근하게 된다. 반대로 application2.swf에서 같은 방식으로 접근할 때 application1.swf로 불려졌다 할지라도 서로 다른 application domain이므로 application2.swf의 com1.Class1에 접근하게 된다. 즉, 자기 자신의 application domain 영역에 정의된 Class를 사용하며 서로 간섭을 일으키지 않는다.
|
var ClassRef:Class = getDefinitionByName("com2.Class2") as Class; |
위의 접근 방식은 <그림 3>에서 application2.swf에서만 사용이 가능하다. com2.Class2는 application2.swf에서 정의되었고 application1.swf의 application domain이 application2.swf의 것과 다르기 때문에 application1.swf에서는 이 Class를 사용할 수 없다. 완전히 다른 application domain 영역이므로 unload시 바로 가비지 컬렉션 대상이 된다.
2.2 ApplicationDomain 사용법B – 부모의 current domain을 사용
|
var loader:Loader = new Loader(); var request:URLRequest = new URLRequest("module1.swf"); var context:LoaderContext = new LoaderContext(); context.applicationDomain = ApplicationDomain.currentDomain; loader.load(request,context); |
위 코드에서 module1.swf는 부모와 같은 application domain을 사용하고 있다. 이것은 부모 프로그램의 자원을 공유하겠다는 의미와 동일하다.
<그림 4> 부모 프로그램과 동일한 application domain을 사용하는 경우
<그림 4>에서 볼 수 있듯이 자식 프로그램인 module1.swf는 부모 프로그램인 application1.swf의 클래스를 사용할 수 있다. 만약 클래스가 부모 프로그램에 정의되어 있지 않는 경우 자식 프로그램에서 정의된 클래스가 부모 프로그램의 application domain에 등록되어 함께 공유하게 된다. 자식 프로그램과 부모 프로그램에 같은 이름의 Class가 존재한다면 자식 프로그램에서 정의한 Class는 무시된다.



