!!! Chapter 4. Bundles and Application Contexts OSGiでの開発単位(またはモジュール単位)は「Bundle」です。(OSGiサービスプラットフォームコア仕様のセクション3.2を参照) OSGiのランタイムに認識されたBundleは次の3つの状態を遷移します。 *「'''installed'''」 *「'''resolved'''」 *「'''active'''」 Bundleはサービス(又はObject)をOSGiサービス・レジストリへエクスポートし、それらのサービスを他のサービスに対して検索したり利用したりできるようにします。 BundleはまたJavaのPackageをエクスポートし、他のBundleからその型(Type)をインポート可能にします。 Springにおいては、第一の境界はアプリケーション・コンテキストです。アプリケーション・コンテキストは複数のBeanを含んでいます。(Springアプリケーション・コンテキストによって管理されているObject群) アプリケーションコンテキストは階層的に設定することも可能です。(例えば、子アプリケーション・コンテキストが親アプリケーション・コンテキストで定義されているbeanが参照できる。しかし、逆は不可。) Springのコンセプトは、「ExporterとFactory beanはアプリケーション・コンテキストの外のクライアントに対してリファレンス(Objectの参照)を提供する」そして、「アプリケーション・コンテキスト外に対して、定義されたリファレンスをインジェクションする、です。 OSGi BundleとSpringアプリケーション・コンテキストには自然な親近感があります。 Spring Dynamic Modulesを使うと、activeなBundleはSpringアプリケーション・コンテキストを持ち、Bundle内部のObjectに対してインスタンス化・設定・組み立て・デコレーションに関して責任を持ちます。 これらのbeanはOSGiサービスに対してExportすることもでき、OSGiサービスに対し透過的にbeanのリファレンスをインジェクションすることを可能にします。 !! 4.1. The Spring Dynamic Modules Extender bundle Spring Dynamic Modulesは「org.springframework.osgi.bundle.extender」というOSGi Bundleを提供します。 このBundleは他のアプリケーションBundleに対してSpringアプリケーション・コンテキストを提供します。 Spring webアプリケーションにおける[「ContextLoaderListener」|http://static.springframework.org/spring/docs/2.5.x/reference/webintegration.html]と同様です。 Extender Bundleがインストールされ起動されると他の既にACTIVE状態のSpring-poweredなBundleを探しに行き、それらの為にアプリケーション・コンテキストを作成します。 それに加え、プラットフォーム内でbundleのstartイベントを監視し、startしたBundleがSpring-poweredであればそれのためのアプリケーション・コンテキストを順次作成していきます。 [[Section 5.1, “Bundle format and Manifest headers”|dm-app-deploy]]でExtender Bundleがどのように「Spring-powered」Bundleを検索するのかを説明し、[[Section 5.2, “Extender configuration options”|dm-app-deploy]]でどのようにExtender Bundleを設定するのかを説明します。 ---- ''(訳注:ここの段落は本文横の囲み記事です)'' ! Extenderパターン OSGiアプリケーションでの共通パターンである「Extender」は、(OSGi Technical Directorの[Peter Kriens|http://www.aqute.biz/Blog/HomePage]より引用すると、)「特定のドメイン内に対して他のBandleが機能拡張すること」です。 [この|http://www.osgi.org/blog/2007/02/osgi-extender-model.html]OSGi Allienceのblogエントリーに詳しい解説があります。 ''(訳注:囲み記事ここまで)'' ---- !! 4.2. Application Context Creation Extender Bundleは非同期にアプリケーション・コンテキストを生成します。この事はOSGiサービス・プラットフォームの起動が遅くなる事と起動時に相互に依存性を持つサービスがデッドロックを起すことを防ぎます。 よって、Spring-poweredなBundleはそのアプリケーション・コンテキストが作成される前に「STARTED」の状態になるかもしれません。 アプリケーション・コンテキストの生成をBundleからBundleへ同期的に強制することも可能です。 アプリケーション・コンテキストの生成の振る舞いの設定については[[Section 5.1, “Bundle format and Manifest headers”|dm-app-deploy]]を参照してください。 アプリケーション・コンテキストの生成が失敗すると、その理由はログされます。そのBundleは「STARTED」の状態のままに置かれます。この場合、アプリケーション・コンテキストからは(OSGi)レジストリに何もexportされません。 ! 4.2.1. Mandatory Service Dependencies アプリケーション・コンテキストがあるOSGiサービスを必須であると宣言している場合、アプリケーション・コンテキストの生成は依存するOSGiサービスがOSGiサービス・レジストリ内で有効になるまでブロックされます。([[Chapter 6, The Service Registry|dm-service-registry]]を参照) OSGi環境内でサービスが起動・終了するときの上記の振る舞いはアプリケーション・コンテキストの作成開始の時点で全ての必須のサービスが有効であることを保障します。 [[Chapter 6, The Service Registry|dm-service-registry]]では必須のサービスが使用不可能な場合に何が起こるかを説明しています。例として、一般的なSpring Dynamic Modulesを使用して作られたエンタープライズ・アプリケーションにおいて、利用可能なサービスとBundleのセットはプラットフォームとそこにインストールされたBundleが全てスタートしてから利用可能状態になります。 このように「必須な依存を待つ」というシンプルな振る舞いは、Bundle AとBにおいて、Bundle BがエクスポートしているサービスにBundle Aが依存しているとなっている場合に、Bundle Bはどのような順番であっても常に起動されているということを表します。 必須な依存が立ち上がるのを待つ場合にタイムアウトが発生する場合があります。 デフォルト状態ではタイムアウトは5分に設定されていますが、「timeout」ディレクティブによってこの値は変更可能です。 詳細については[[Section 5.1, “Bundle format and Manifest headers”|dm-app-deploy]]を参照してください。 アプリケーション・コンテキストを作成する際に必要なサービスが立ち上がっていない場合、スタートアップの時点で即座にアプリケーション・コンテキストの生成を「失敗」とすることもできます。(セクション4.1を参照) 依存先を待たない設定にしてある場合、そのBundleは停止し、「RESOLVED」の状態になります。 ! 4.2.2. Application Context Service Publication あるBundleに対してアプリケーション・コンテキストの生成が完了すると、「アプリケーション・コンテキスト」オブジェクトはOSGiサービス・レジストリを通してサービスとして自動的にエクスポート(公開)されます。 アプリケーション・コンテキストはInterface「org.springframework.context.ApplicationContext(と、継承している全ての可視のSuper Interface)」として公開されます。 公開されたサービスは「org.springframework.context.service.name」というサービス・プロパティーを持ち、値はアプリケーション・コンテキストをホストするBundleのシンボリック名(symbolic name)にセットされます。 BundleのManifest内のディレクティブでアプリケーション・コンテキストをサービスとして公開されることを防ぐこともできます。 詳細は[[Section 5.1, “Bundle format and Manifest headers”|dm-app-deploy]]を参照してください。 '''Note:''' アプリケーション・コンテキストのサービスとしての公開は主にテストや管理を促進するためのものです。 実行時に他のアプリケーション・コンテキストに対してgetBean()やそれと同じ方法でアクセスすることは好ましくありません。 他のアプリケーション・コンテキストで定義されているbeanに対するアクセスは、そのbeanをOSGiサービスとしてエクスポートし、使用側ではそのサービスをインポートして参照するという形で行われるべきです。 OSGiサービスレジストリを通したアクセスはサービスタイプのバージョン互換性があるサービスだけを可視とすることができ、OSGiプラットフォームの流儀を尊重することができます。 !! 4.3. Bundle Lifecycle OSGiは動的なプラットフォームです。各Bundleはプラットフォーム内でいつでもインストール、開始、アップデート、停止そしてアンインストールされるか可能性があります。 アクティブだったBundleが停止されると、そのBundle生存中に公開していた全てのサービスは登録解除され、Bundleは「resolved」のステートに移ります。 停止されたBundleはその使用していた全てのリソースを開放し、作成したスレッドを削除(terminate)します。しかし停止されたBundleによって公開されていたpackageはその後も他のBundleから参照可能です。 「resolved」のステートにあるBundleはアンインストールされるかもしれません。アンインストールされると、公開していたpackageは既にそのpackageをインポートしていたBundleからは使用し続けることができますが、新たなBundleがそのpackageをインポートしようとすることはできません。 「resolved」のステートにあるBundleはアップデートされるかもしれません。アップデートとはあるBundleを異なったバージョンの同じBundleに変えることです。 最後に、もちろん、「resolved」なステートにあるBundleは開始させることができます。開始されるとそのBundleのステートはアクティブになります。 OSGiの「PackageAdmin refreshPackages」操作はOSGiフレームワークか指定されたインストール済みのBundleのpackageをリフレッシュします。 リフレッシュ中は、対象のBundle内のアプリケーション・コンテキストは停止され、再起動されます。 refreshPackagesの後、アップデート以前のバージョンのBundleから公開されていたpackage、またはアンインストールされたバージョンのBundleから公開されていたpackageは使うことができなくなります。 これらの動きの詳細はOSGiの仕様の中で定義されています。 Spring-poweredのBundleが停止された場合、自動生成されたアプリケーション・コンテキストは削除されます。 Bundleによって公開されていた全てのサービスは登録解除されます(サービス・レジストリから削除されます)。そして、アプリケーション・コンテキストの通常のtear-downライフサイクルが実行されます。(アプリケーション・コンテキスト内のorg.springframework.beans.factory.DisposableBean Interfaceの実装と、「destory-method」で指定されたcallbackが実行されます。) Spring-poweredのBundleが停止された後に再起動された場合、新しいアプリケーション・コンテキストが作成されます。 !! 4.4. The Resource abstraction Spring Frameworkはアプリケーション・コンテキスト内へのリソースのロードにおいてリソースの抽象化を行います。(Spring's resource abstractionを参照。) 全てのリソース読み込みはアプリケーション・コンテキストのorg.springframework.core.io.ResourceLoaderを通して行われます。 org.springframework.core.io.ResourceLoaderはリソースをコード内から読み出したいbeanについても使用されます。 特定の接頭辞(プリフィクス)、例えば「classpath:」がついたリソースへのパスはアプリケーション・コンテキストのタイプにかかわらず同様に扱われます。(例えば、Webアプリケーションのコンテキストでも、classpathベースのアプリケーション・コンテキストでも。) リソースへの相対パスはアプリケーション・コンテキストのタイプに応じたベースからのパスに解釈されます。 これにより最終的な配置場所の外での結合テストを簡単にします。 OSGi 4.0.x仕様ではリソースを読み込むことのできる3つの空間を定義しています。 Spring-DMはOSGi仕様によるアプリケーション・コンテキストとprefixによって、その3つ全てをサポートしています。 '''Table 4.1. OSGi resource search strategies''' ,OSGi検索方式,プレフィクス,説明 ,Class空間,classpath:,Bundle classloaderを検索(そのbundle、 全てのimportされたpackageと必須のBundle)。Bundleは強制的に解決されます。この方法は[Bundle#getResource(String)|http://www2.osgi.org/javadoc/r4/org/osgi/framework/Bundle.html#getResource(java.lang.String)]と同じです。 ,Class空間,classpath*:,Bundle classloaderを検索(そのbundle、 全てのimportされたpackageと必須のBundle)。Bundleは強制的に解決されます。この方法は[Bundle#getResource(String)|http://www2.osgi.org/javadoc/r4/org/osgi/framework/Bundle.html#getResource(java.lang.String)]と同じです。 ,JARファイル(又はJarSpace), osgibundlejar:,Bundle jarだけを検索する。Bundleを新たに解決することなくローレベルのアクセスだけをする。 ,Bundle space,osgibundle:,Bundle jarとアタッチされたフラグメント(もしあれば)だけを検索する。classloaderを作成したりBundleを解決したりはしない。 これらの詳細な違いについての説明はOSGi仕様のsection 4.3.12を参照してください。 '''Note''' prefixを省略した場合は、Bundle space(osgibundle:)が指定されたものとみなされます。 '''Note''' OSGiの動的機能によって、Bundle classpthはライフサイクル中に変更されることがあります。(例えば、ダイナミック・インポートが使用された場合。) これによって、実行環境やターゲット・プラットフォームによってパターン・マッチングによるclasspathリソースに差異が生じるかもしれません。 「file:」や「http:」などのようなSpring標準のリソース・プレフィクスも全てサポートされ、ワイルドカードによるパターン・マッチングも行えます。 これらのプレフィクスを使用することによって、リソースを読み込んでいるBundleやアタッチされているフラグメントにかかわらず、どこからでもそのリソースを読むことができます。 OSGiプラットフォームはプラットフォーム毎に独自のプレフィクスが定義されています。例えば、Equinoxでは「bundleresource:」「bundlentry:」などがあります。 これらのプラットフォーム独自のプレフィクスは、もちろん、必要に応じて、ターゲットとなるOSGi実装ごとに、Spring OSGiなどのプレフィクスと一緒に使うことができます。 !! 4.5. Accessing the BundleContext 一般的に、Spring Dynamic Modulesを使う場合にOSGiのAPIを使う必要はありません。 もしOSGi BundleContextにアクセスする必要が生じたとしても、Springを使ってそれを簡単に行うことができます。 SpringExtenderによって作成されたOSGiアプリケーション・コンテキストは自動的に「BundleContext」タイプの「bundleContext」いう名前のbeanを持っています。 アプリケーション・コンテキスト内では型からでも名前でもこのbeanへの参照をインジェクションできます。 さらに、Spring Dynamic Modulesはorg.springframework.osgi.context.BundleContextAwareインターフェースを提供しています。 public interface BundleContextAware { public void setBundleContext(BundleContext context); } このインターフェースをimplementsしたbeanはSpringによって設定時にBundle Contextがインジェクションされます。 Bundle内でこの機能を使うのであれば、そのBundle Manifest内にorg.springframework.osgi.contextパッケージをimportするのを忘れないでください。 !! 4.6. Application Context Destruction アプリケーション・コンテキストはその生存期間中Bundleに結び付けられています。 よって、定義されているBundleがシャットダウンを始めた場合、アプリケーション・コンテキストもまた、全ての公開中のサービスを登録解除し、インポートしている全てのサービスを開放して、破棄されます。 しかしながら、Bundleは個別に破棄される場合も、OSGiプラットフォーム全体のシャットダウンの一環として破棄される場合も両方ありえることを忘れないでください。 この場合またはExtender Bundleがシャットダウンを始めた場合、管理されているアプリケーション・コンテキストはそれらの間の依存性に基づいた手順でシャットダウンされます。 詳細は次のセクションを参照してください。 !! 4.7. Stopping the extender bundle Extender Bundleが停止されると、Extender Bundleによって作成された全てのアプリケーション・コンテキストは破棄されます。 アプリケーション・コンテキストは以下の順番でシャットダウンされます。 ++ 何もサービスを公開していないアプリケーション・コンテキスト、または公開しているサービスがどこにも参照されていないアプリケーション・コンテキストがBundle IDの逆順にシャットダウンされます。(最も最近にインストールされたBundleのアプリケーションコンテキストが最初にシャットダウンされます。) ++ 上記の対象のアプリケーション・コンテキストがシャットダウンされることによってその中に保持されていた他のサービス参照が開放される為、さらに上記条件に当てはまるアプリケーション・コンテキストが出てきます。よって、上記ステップを繰り返します。 ++ アクティブなアプリケーション・コンテキストがなくなったら完了です。それでもアクティブなアプリケーション・コンテキストが残っているとしたら、それは循環参照です。循環参照の解消は各コンテキストで最上位のランク''(訳注:the highest ranking service)''の公開されているサービスによって決定されます。この循環参照の中で最下位のランクのサービスがシャットダウンされます。(または同位の場合は、一番大きいサービスID)その後、最初のステップが繰り返されます。 ---- [[次へ|dm-app-deploy]] [[前へ|dm-reference]] [[目次へ|sdm_index]] [[技術的雑談へ戻る|技術的雑談]]