본문 바로가기

Blog/Flex

Application의 컴파일에서 SWF가 실행될 때까지

Application 이 작성되어 swf로 컴파일된 후 런타임에 실행되는 과정을 살펴 보기 위해 간단한 Application mxml을 만들고 컴파일 옵션에 다음을 추가합니다.

-keep-generated-actionscript=true

임의로 aa.mxml 이라는 Application을 만들어 컴파일을 시켜보면 여러 파일들이 generated 폴더에 자동으로 생성되는데 이 파일 중에 몇 가지 파일의 내용을 참고로 살펴봅니다. 관심 외 코드는 삭제하였습니다.

[aa.mxml]
(Application 파일)

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="onCreationComplete(event);">
    <mx:Script>
        <![CDATA[
            
private function onCreationComplete(event:Event):void
            {
                
trace("onCreationComplete");
            }
        ]]>
    
</mx:Script>
</mx:Application>

컴파일하면 자동 생성되는 파일의 내용입니다.

[aa-generated.as]
( aa.mxml 이 aa 클래스로 변환됩니다. Application 클래스를 상속 받았죠.)

[Frame] 메타데이터 태그는 컴파일러로 하여금 두 프레임을 가진 SWF를 만들도록 합니다. 그런 후 첫 번째 프레임에는 factory class와 factory class 에서 사용하는 class들, Embedded Asset을 집어넣고, 두 번째 프레임에는 그외 나머지 Embedded Asset들과 main class, main class에서 사용하는 다른 class들을 모두 집어 넣습니다. 말하자면 두 프레임을 가진 MovieClip 의 Document Class 가 바로 SystemManager인 것입니다. 그림으로 표현하자면 다음 그림과 같습니다. (http://www.bit-101.com/blog/?p=946 내용중 Frame 메타데이터 태그에 대한 내용이 있다. 참고 )

따라서 아래 aa 클래스는 먼저 _aa_mx_managers_SystemManager 클래스를 Document Class로 사용하여 위와 같은 구조를 갖추게 되고, 이제부터 이 SWF는 모든게 SystemManager의 통제하에서 이후 절차가 진행되게 되는 겁니다. 정작 Application 인스턴스는 SystemManager 클래스의 create()메서드를 통해 Application (aa 클래스)의 인스턴스를 만들고 있습니다.

package
{    
    
[Frame(factoryClass="_aa_mx_managers_SystemManager")]
    
public function aa()
    {
        
super();
        mx_internal::_document =
this;
        mx_internal::_aa_StylesInit();

        
// <mx:Application> 태그의 attribute 내용 적용
        this.layout = "absolute";
        
// 대부분 이벤트 설정은 아래와 같이 적용됩니다. 핸들러 메서드로 일정한 작명 규칙에 의해 자동으로 생성 된다는걸 예상이 드는군요.
        
this.addEventListener("creationComplete", ___aa_Application1_creationComplete);
    }

    
override public function initialize():void
    {
        mx_internal::setDocumentDescriptor(_documentDescriptor_);
        
super.initialize(); // FlexEvent.PREINITIALIZE 이벤트가 발생함.
    }
    
// 이벤트 호출
    public function ___aa_Application1_creationComplete(event:mx.events.FlexEvent):void
    {
        
// <mx:Application> 태그의 creationComplete="" 의 내용이 그대로 복사됩니다.
        onCreationComplete(event);
    }

    
// aa.mxml 의 <mx:Script> 태그 내용 (CDATA 내용)이 그대로 복사됩니다.
    private function onCreationComplete(event:Event):void
    {
        
trace("onCreationComplete");
    }
}

Frame 메타데이터 태그를 제외하고는 별다른 사항이 없습니다. 어차피 Application 의 대부분은 사용자가 직접 작성한 코드에 의해 돌아갈 테니까요.

그럼 제일먼저 인스턴스화되는 factory class를 살펴보겠습니다. 아래 코드에는 나타나 있지는 않지만 SystemManager 에서는 실제로 Preloader 를 생성, 표현하고 로드 완료 시점에 Application 객체를 생성하는게 주된 일입니다.

[_aa_mx_managers_SystemManager-generated.as]
(SystemManager를 상속 받고 IFlexModuleFactory를 구현합니다.)

IFlexModuleFactory 는 동적으로 로드된 module이나 Flex applications 을 로드하여 초기 구동 시키기는 역할을 하는 요소를 포함합니다. create() 메서드는 SystemManager가 2프레임으로 넘어갔을 때 호출됩니다. 언급한대로 Application 클래스의 파생 클래스인 aa 클래스를 인스턴스화 하고 있습니다. 부모 클래스인 SystemManager의 코드 흐름 속에서 생성의 의무를 파생클래스에서 담당하도록 하는 전형적인 Factory Method 패턴 구조입니다.

package
{
    
public class _aa_mx_managers_SystemManager extends mx.managers.SystemManager implements IFlexModuleFactory
    {
        
public function _aa_mx_managers_SystemManager()
        {
            FlexVersion.compatibilityVersionString =
"3.0.0";
            
super();
        }

        
override public function create(... params):Object
        {
            
if ( params.length > 0 && !( params[0] is String ) )
                
return super.create.apply(this, params);

            
var mainClassName:String = params.length == 0 ? "aa" : String(params[0]);
            
var mainClass:Class = Class(getDefinitionByName(mainClassName));

            
if ( !mainClass )    return null;

            
var instance:Object = new mainClass();
            
if ( instance is IFlexModule )
                ( IFlexModule(instance) ).moduleFactory =
this;
            
return instance;
        }

        
override public function info():Object
        {
            
return { compiledLocales: [ "en_US" ],
                compiledResourceBundleNames: [
"containers", "core", "effects", "skins", "styles" ],
                creationComplete:
"onCreationComplete(event);",
                currentDomain: ApplicationDomain.currentDomain,
                layout:
"absolute",
                mainClassName:
"aa",
                 …
                }
        }
         …
    }
}

SystemManager에 대한 자세한 사항은 여기 (http://vulcan9.tistory.com/18) 를 참고하세요