Loader オブジェクトで (URLLoader ではありません) swf ファイルをロードするとき、ロード先のアプリケーションドメインを指定することができます。
アプリケーションドメインはクラス定義の単位になるため、実行時に swf をロードすることで動的にクラス定義を追加するといった使い方ができます。また、複数のアプリケーションドメインを持つことができるため、同じクラスの異なるバージョンを同時にアプリ内で使うことも可能です。
それでは、アプリケーションドメインの使い方について詳しく見ていきましょう。
アプリケーションドメインの階層
通常、アプリケーションドメインは階層構造をなしています。一番親のアプリケーションドメインはシステムドメインと呼ばれ、Flash Player 上に一つだけ存在します。その他のアプリケーションドメインはシステムドメインの子孫ということになります。
各アプリケーションドメインにはクラス定義が含まれますが、子のドメインは親のドメインのクラス定義を引き継ぎます。従って、下の階層になるほど多くのクラスが利用可能なわけです。
アプリケーションドメインは ApplicationDomain クラス (livedocs@lab) のインスタンスとして実装されています。ApplicationDomain のインスタンスを生成する際、親ドメインをコンストラクタの引数として指定することができます。何も指定されなければシステムドメインが親ドメインになります。
// システムドメイン下に新しいアプリケーションドメインを作成 new ApplicationDomain(); // 現在のドメイン下に新しいアプリケーションドメインを作成 new ApplicationDomain(ApplicationDomain.currentDomain);
ApplicationDomain.currentDomain は現在アプリケーションが実行されているドメインを示す静的変数です。
ロード時のアプリケーションドメインの指定
swf ファイルロード時に読込先のアプリケーションドメインを指定するには URLRequest オブジェクトの applicationDomain 属性を使用します。
var myReq:URLRequest = new URLRequest(); myReq.url = "myClasses.swf"; // 現在のドメインを設定する myReq.applicationDomain = ApplicationDomain.currentDomain; var myLoader:Loader = new Loader(); myLoader.load(myReq);
読み込み後は Loader の loadeeInfo 属性から myLoader.loadeeInfo.applicationDomain のようにして読み込まれた swf が属するアプリケーションドメインにアクセスすることができます。
読み込まれた側から自身の属するアプリケーションドメインを取得するには、読み込まれた swf 内のルート DisplayObject の loaderInfo から参照します。roo 以外の DisplayObject からであれば this.root.loaderInfo.applicationDomain で取得できます。
getClass() メソッドによる動的なクラス定義の利用
さて、getClass() メソッドを使うとアプリケーションドメインからクラス定義を取得することができます。つまり、アプリケーションドメインに新しく swf ファイルを読み込むことで、利用できるクラス定義を動的に追加できるわけです。
ただし既存のクラス定義を、新しくロードした swf 内の定義で上書きすることはできません。新規に見つかったクラス定義のみが追加されます。
var myReq:URLRequest = new URLRequest(); myReq.url = "myClasses.swf"; // 現在のドメインに読み込むよう指定 myReq.applicationDomain = ApplicationDomain.currentDomain; var myLoader:Loader = new Loader(); myLoader.addEventListener(Event.COMPLETE, completeHandler); myLoader.load(myReq); private function completeHandler(event:Event):void { // まず読込先のドメインを取得 var myDomain:ApplicationDomain = myLoader.loadeeInfo.applicationDomain; // ドメイン内のクラス定義を取得 var myClassRef:Class = myDomain.getClass("myClass1"); // 定義を取得したクラスのインスタンス生成 var foo:Object = new myClassRef(); }
上記の例ではアプリケーションを実行中のアプリケーションドメインに swf をロードしています。この場合、一旦追加されたクラス定義はそのまま残り続けます。
ですが、子のドメインに swf をロードすれば swf をアンロードすることで追加されたクラス定義もガーベッジコレクションの対象とすることができます。(もちろんロードした swf への参照がないことが条件ですが)
つまり、下のように書き換えた場合にはクラス定義の追加と削除がコントロールできるようになるわけです。
... myReq.url = "myClasses.swf"; // 新規に子ドメインを作るよう変更 myReq.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain); var myLoader:Loader = new Loader(); myLoader.addEventListener(Event.COMPLETE, completeHandler); myLoader.load(myReq); ...
別ドメインへのアプリケーションのロード
アプリケーションを読み込むときにアプリケーションドメインを使い分けることで、クラス定義への依存状況に柔軟に対応することができるようになります。
例えば、システムドメイン直下に新しいアプリケーションドメインを作成した場合、現在のドメインと新規ドメインのクラス定義は独立です。すなわち、アプリケーション固有のクラス定義は共有されません。
これを利用すると、同じアプリケーションの異なるバージョンを、クラス定義の違いなどを気にすることなく同時に実行することが可能です。
var myReq:URLRequest = new URLRequest(); // 別バージョンのアプリケーションを指定 myReq.url = "v2app.swf"; // システムドメイン下に新しいアプリケーションドメインを作成 myReq.applicationDomain = new ApplicationDomain(); var myLoader:Loader = new Loader(); // 独立した新規ドメインにアプリケーションをロード myLoader.load(myReq);
また、複数の子ドメインにアプリケーションを分割すると、子ドメイン固有のクラス定義はそれぞれ独立させながら、親ドメインを共通のクラス定義の場として管理することができます。
例として、複数のパネルを持つポータル系のアプリケーションで、個々のパネル内を独立したアプリケーションとして実装した場合を考えてみます。
// パネル内のアプリケーションを指定 myReq1.url = "panel1.swf"; // 新規に子ドメインを作成 myReq1.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain); myLoader1.load(myReq); // 別パネル内のアプリケーションを指定 myReq2.url = "panel2.swf"; // もう一つ子ドメインを作成 myReq2.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain); myLoader2.load(myReq);
このような構造だと panel1.swf に固有のクラス定義は例えば panel2.swf のような他のパネル内のアプリケーションには影響しません。そのため、共通部分(親のアプリケーションドメイン内のクラス定義)は管理しながら、かなり自由に個別の機能を開発/管理することができそうです。
お世話になります。
『アプリケーションドメイン』とは考え方としては『Namespace』に近いのでしょうか?
また、別のサーバーのSWFをロードすることはできるのでしょうか?
ぺぺさん
こんにちは。
ご指摘のようにどちらもリソースを管理する単位になるという点は共通です。一方、使われる状況や目的は異なります。Namespace は「コンパイル時に既知のリソース」に対するアクセスをコントロールするものですが、ApplicationDomain (+Loader) は実行時にアクセスしたいリソースをコントロールするために使われます。
また、別サーバからの読み込みにはポリシーファイルが必要です。詳しくはこちらの記事を参考にしてください。
http://www.macromedia.com/jp/devnet/flash/articles/fplayer_security_03.html