OSGiコンテナーでのSpringの使用







Spring Frameworkが何であるかを知らないJava開発者はほとんどいません。 このフレームワークのコアテクノロジーの1つは、IoCコンテナーとAOPサポートです。 これらのテクノロジーにより、実行時にクラスレベルとオブジェクトレイアウトレベルの両方で、アプリケーションアーキテクチャを個別のレイヤーに正常に分解することができます。 アプリケーションは要素/レイヤーに完全に構​​造化されているように見えますが、本質的にはモノリシックのままです。 実行時にキャップレス! このフレームワークのフレームワーク内でのみ、この問題に対する普遍的な解決策はありません。 OSGiについて聞いたことのあるJava開発者はわずかです。 これは、Javaプラットフォーム用のモジュラーシステムの仕様です。 この仕様の特定の実装をアプリケーションの基礎として使用すると、実行時と物理レベル(ファイルレベル)の両方でモジュール化することができます。 これらの技術の相乗効果については、この記事で説明します。



春のフレームワーク



読者が少なくとも公式ガイドの最初の10章を読むレベルで、このフレームワークに精通していることを願っています。 このすべてを1つの記事で説明することはできません。 したがって、私はそれを必要とするすべての人を公式の指導者に送ります。 以下は、Spring Frameworkの主要コンポーネントのクイックリファレンスです。



SpringSourceポートフォリオのさまざまなサブプロジェクト。



モジュール性



理想的には、真のモジュラープログラムは、次の明確な機能を備えた要素で構成する必要があります:弱い接続(明確に定義されたインターフェースを介した相互作用、簡単な交換性、複数の使用)、カプセル化(モジュールは外部から特定の相互作用インターフェースを備えたブラックボックスとして表示されます)、ダイナミズム(実行時に多くのモジュールを変更する機能)。 Javaでは、クラスレベルとパッケージレベルの両方で、疎結合とカプセル化を実装できます。 もちろん、リフレクション(Reflection API)を使用してアクセス修飾子(プライベート、保護)のレベルでカプセル化を解除し、コードをサードパーティコードの内部メカニズムにリンクする方法、またはクラスコードを変更するメカニズム(javassist、cglib、クラスコードを手動で変更するなど)を使用する方法があります.d。)、しかしそれはハッキングのようなものです。 しかし、ダイナミズム、つまり、実行時にモジュールを置き換える機能についてはどうでしょう。 この分野では事態はさらに悪化しています。 もちろん、クラスローダーを実装で再定義することにより、ダイナミズムのサポートを実装できますが、これはOSGi標準実装の開発者がすでに行った非常に大量の作業です。 OSGiコンテナはすべて、コアアーキテクチャおよびAPIレベルでモジュール性を既にサポートしています。



OSGi



Open Services Gatewayイニシアチブは、多くの実装を伴う仕様です。 主要なオープンソースの実装は、Apache Felix、Equinox、およびKnopflerfishです。 この仕様では、さまざまなモジュール(バンドル)を動的にバインドできるモジュラーシステムについて説明します。 モジュールの構成は、実行時に変更される場合があります。 モジュール間の相互作用は、サービスレジスタ(Service Register)に登録されているサービスを使用して実行されます。 モジュールには、いくつかの状態(インストール済み、解決済み、開始中、アクティブ、停止中、未インストール)で構成されるライフサイクルがあります。 モジュールのライフサイクルは、OSGiコンテナによって制御されます。









モジュール状態図



OSGiモジュール(バンドル)には、META-INF / MANIFEST.MFファイルに追加のメタデータが必要です。 主なもののいくつかを以下に示します。





OSGiでSpringを使用する機会をどのようにして得ましたか



OSGi実装により、真のモジュラーJavaプログラムを作成できます。 Spring Frameworkを使用すると、IoCコンテナーを使用してオブジェクトの関係を手動でサポートする必要がなくなり、AOPを使用して既存のクラスの機能を拡張し、SpringSourceポートフォリオの関連テクノロジーを使用できます。 これらの技術の組み合わせは、ソフトウェア開発に大きな利益をもたらすはずです。 驚くことではありませんが、2006年にInterface21(後のSpringSource)の人々がこのアイデアを思いつき、OSGi Alliance、BEA、Oracle、IBMの人々を開発に結び付けることができました。 共同の努力の結果、Spring dm製品がSpringSourceウィングの下に現れ、後にこの製品はOSGi Service Platform Service Compendiumのブループリント仕様を生み出しました。 そのコードベースはEclipse Foundationに引き継がれ、Gemini Blueprintと名付けられました。 SpringSourceはdm Serverもリリースし、そのコードベースはEclipse FoundationのVirgoプロジェクトになりました。



Gemini Blueprint Architecture(Spring DM)



Gemini BlueprintはOSGiコンテナーでSpring Frameworkをどのように使用しますか? この質問に答えるには、Gemini Blueprintアーキテクチャの主要なポイントを考慮する必要があります。



アーキテクチャの基本要素はエクステンダー(OSGiパターンのエクステンダーの実装)です。 Extenderは、OSGiサービスプラットフォームの新しいモジュール(バンドル)の起動イベントを監視し、このモジュールがブループリント仕様をサポートしているかどうかを確認します。 モジュールがこの仕様をサポートしている場合、エクステンダーはモジュールのSpringコンテキストを作成して初期化します。 したがって、各Springモジュールには独自のSpringコンテキストがあります。 さらに、Spring-beanをOSGiサービスとして公開し、OSGiサービスへのリンクを受信するなどの処理を行うコードは、エクステンダーから呼び出されます。









エクステンダー操作図



エクステンダーがコンテキストを作成する基礎となるすべての情報は、xmlファイルの形式で構成から取得されます。 ここでは、スプリングとブループリントの2つの可能な構成オプションの存在を強調する必要があります。 どちらのオプションも多くの点で似ていますが、最初のオプションがネイティブSpring構成に対応し、サービスを構成するための追加の名前付きスペースがある場合、2番目のオプションはBlueprint OSGi Service Platform Service Compendium仕様で明確に定義されています 実際、Spring dmと下位互換性のある3番目のオプションもあります。

アーキテクチャの詳細な研究については、記事の最後にあるリンクを参照してください。



Gemini BlueprintとOSGiの使用例





使用例として、2つのサービス実装と1つのクライアントを持つGUIアプリケーションを作成します。 この例では、Gemini Blueprintを使用してOSGiプログラムの開発を促進する方法を示します。 まず、OSGi APIを使用する必要はありません。 第二に、サービスのダイナミズムの問題は、ジェミニブループリントによって独自に決定されます。アプリケーションロジックを処理するだけです。 第三に、Spring Frameworkを使用してアプリケーションを構築します。



アプリケーションはmaven 3を使用して構築されます。プロジェクトのファイル構造は次のとおりです。



 blueprint-example
 ├──消費者
 │├──pom.xml
 │└──src
 │├──メイン
 ││├──java
 │││└──青写真
 │││└──例
 │││└──消費者
 │││├──ConsumerFrame.java
 │││├──Consumer.java
 │││└──RefreshListener.java
 ││└──リソース
 ││└──META-INF
 ││└──スプリング
 ││├──osgi-context.xml
 ││└──spring-context.xml
 │└──テスト
 │├──java
 │└──リソース
 ├──日付作成者
 │├──pom.xml
 │└──src
 │├──メイン
 ││├──java
 │││└──青写真
 │││└──例
 │││└──dateproducer
 │││└──ProducerImpl.java
 ││└──リソース
 ││└──META-INF
 ││└──スプリング
 ││├──osgi-context.xml
 ││└──spring-context.xml
 │└──テスト
 │├──java
 │└──リソース
 ├──int-producer
 │├──pom.xml
 │└──src
 │├──メイン
 ││├──java
 │││└──青写真
 │││└──例
 │││└──intproducer
 │││└──ProducerImpl.java
 ││└──リソース
 ││└──META-INF
 ││└──スプリング
 ││├──osgi-context.xml
 ││└──spring-context.xml
 │└──テスト
 │├──java
 │└──リソース
 ├──pom.xml
 └──producer-api
     ├──pom.xml
     └──src
         ──メイン
         │├──java
         ││└──青写真
         ││└──例
         ││└──プロデューサー
         ││└──api
         ││└──Producer.java
         │└──リソース
         │└──META-INF
         └──テスト
             ├──java
             └──リソース




ディレクトリのconsumer、producer-api、date-producer、およびint-producerは、それぞれクライアントのプロジェクト、サービスAPI、日付と整数に基づくサービス実装です。 わかりにくいですか? 心配しないでください、今から順番に取ります。



これらのプロジェクトはそれぞれ、OSGiコンテナー用の個別のモジュール(バンドル)です。 producer-apiプロジェクトには、Producerインターフェイスを持つファイルが1つだけ含まれています。 これは、OSGiアプリケーションAPIを個別のモジュールに分離する典型的な例であり、それを必要とするすべてのモジュールによってインポートされます。 このモジュールは、必要なクラスを提供することのみを目的としているため、ブループリントモジュールではありません。



すべてのモジュールをビルドするには、maven-bundle-pluginが使用されます。 これは、コード内でBndユーティリティを使用するApache Felix開発者のプラグインです(OSGiサークルで有名です)。 このプラグインは次のように構成されます。



<plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>2.3.5</version> <extensions>true</extensions> <configuration> <instructions> <Bundle-Name> ${name} ${version} </Bundle-Name> <Bundle-SymbolicName> ${groupId}.${artifactId} </Bundle-SymbolicName> <Export-Package> blueprint.example.producer.api </Export-Package> <Import-Package>*</Import-Package> </instructions> </configuration> </plugin>
      
      





注意深い読者は、命令セクションのエントリの名前がMETA-INF / MANIFEST.MFのOSGiモジュールのメタデータの特定のヘッダーの名前と一致することに注意する必要があります。 これは、自然な形ではなく、bnd命令の形であるということです。 このユーティリティは非常にインテリジェントで、コードの依存関係を計算し、Import-Packageセクションでそれらを置き換えることができ、さまざまなメタデータを追加できます。 その構成と計算に基づいて、MANIFEST.MFを生成します。 この場合、メインの見出しのみを定義します。



エクステンダーがモジュールをブループリントモジュールとして認識するためには、デフォルトで次のルールが使用されます:モジュールのxml構成ファイルはMETA-INF / springディレクトリにあるか、構成場所を示すSpring-Contextヘッダーが必要です。 上記のプロジェクトは、META-INF / springディレクトリにある2つの構成ファイルを使用します。 最初にosgi-プレフィックスが付いているものには、ブループリント固有の構成が含まれています。 接頭辞が「spring-」の2番目には、springアプリケーションの通常の構成が含まれています。

日付および任意の整数に基づくサービスの実装を検討してください。



 @Component public class ProducerImpl implements Producer { @Override public String produceString() { return new Date().toString(); } } @Component public class ProducerImpl implements Producer { private Random random = new Random(new Date().getTime()); @Override public String produceString() { return String.valueOf(random.nextInt()); } }
      
      





このケーススタディのサービスは、任意の文字列を返す1つのStringproduceString()メソッドを持つクラスです。 最初の場合、ローカライズされた日付、2番目の場合、任意の整数を持つ文字列。 これらのモジュールのスプリング構成では、注釈付きクラスをスキャンするプロセスが指定されています。 サービスはosgi構成に登録されます。



 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <context:annotation-config/> <context:component-scan base-package="blueprint.example"/> </beans> <?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.eclipse.org/gemini/blueprint/schema/blueprint" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation=" http://www.eclipse.org/gemini/blueprint/schema/blueprint http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd "> <service id="producerService" ref="producerImpl" interface="blueprint.example.producer.api.Producer"/> </beans:beans>
      
      





開発者の生活を簡素化する約束の例は次のとおりです。 OSGi APIを使用してサービスを登録する必要はありません。xml構成を入力するだけです。



最後のモジュールを検討します。 サービスのクライアントは、テキスト表示フィールドと値更新ボタンを備えたGUIフォームを表示します。 クライアントのコードを見てみましょう。



 @Component public class Consumer { @Autowired private ConsumerFrame consumerFrame; @Autowired private Producer producer; @PostConstruct public void start() { consumerFrame.setRefreshListener(new RefreshListener() { @Override public String refresh() { return producer.produceString(); } }); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { consumerFrame.setVisible(true); } } ); } }
      
      





Consumerクラスは非常に単純です。 コンテナによって挿入される2つの属性が含まれます。 これはフォームオブジェクトであり、サービスへのリンクです。 次に、オブジェクトの構築後に呼び出されるメソッドで、更新イベントのリスナーがサービスアクセスコードと画面にフォームを表示するためのコードで登録されます。 このプロジェクトのスプリング構成は上記の構成と同じに見え、osgi構成は次のようになります。



 <?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.eclipse.org/gemini/blueprint/schema/blueprint" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation=" http://www.eclipse.org/gemini/blueprint/schema/blueprint http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd "> <reference id="producer" interface="blueprint.example.producer.api.Producer"/> </beans:beans>
      
      





この構成では、サービスリンクが登録されます。 デフォルトでは、このサービスは必須であり、このサービスへのすべての呼び出しは、存在しない場合、特定の間隔でブロックされ、その後例外が発生します。 この動作は完全に構成可能です。



Spring Frameworkに精通したプログラマーにはおそらく疑問があります。 サービスへのリンクは、このサービスのダイナミズムをどのように提供しますか? 結局、すべてのオブジェクトはダウンロード段階(熱心)またはアクセス段階(遅延)で構成されます。 プロデューサーリンクがサービスの消失により関連性を失った場合、どうなりますか。 回答:これは青写真で処理されます。 実際、プロキシオブジェクトはサービスへの参照として注入され、ダイナミズムを提供します。 このオブジェクトは、コールブロッキング動作と例外のスローを提供します。



ソースコードを含むアーカイブには、それに加えて、設定された分点コンテナとすべての必要なライブラリ(equinox-for-exampleなど)を含むディレクトリがあります。 これにより、クイックスタートが容易になると思います。 コンテナを起動するには、コンテナを含むディレクトリに移動して、コマンドを実行します:



 java -jar org.eclipse.osgi_3.6.2.R36x_v20110210.jar -console


その後、初期化モジュールからのメッセージが画面に表示されます。 最後に、equinoxコマンドプロンプト。 ssコマンドを入力すると、出力は次のようになります。



 osgi> ss

フレームワークが起動します。

 ID状態バンドル
 0 ACTIVE org.eclipse.osgi_3.6.2.R36x_v20110210
 1アクティブcom.springsource.net.sf.cglib_2.2.0
 2アクティブcom.springsource.org.aopalliance_1.0.0
 3アクティブcom.springsource.org.apache.log4j_1.2.16
 4アクティブcom.springsource.slf4j.api_1.6.1
                    フラグメント= 5
 5解決済みcom.springsource.slf4j.log4j_1.6.1
                    マスター= 4
 6アクティブcom.springsource.slf4j.org.apache.commons.logging_1.6.1
 7 ACTIVE org.eclipse.gemini.blueprint.core_1.0.0.RELEASE
 8 ACTIVE org.eclipse.gemini.blueprint.extender_1.0.0.RELEASE
 9 ACTIVE org.eclipse.gemini.blueprint.io_1.0.0.RELEASE
 10 ACTIVE org.springframework.aop_3.0.6.RELEASE
 11 ACTIVE org.springframework.asm_3.0.6.RELEASE
 12 ACTIVE org.springframework.aspects_3.0.6.RELEASE
 13 ACTIVE org.springframework.beans_3.0.6.RELEASE
 14 ACTIVE org.springframework.context_3.0.6.RELEASE
 15 ACTIVE org.springframework.context.support_3.0.6.RELEASE
 16 ACTIVE org.springframework.core_3.0.6.RELEASE
 17 ACTIVE org.springframework.expression_3.0.6.RELEASE


これは、現在インストールされているすべてのモジュールのリストです。 次に、テストアプリケーションをインストールする必要があります。 これを行うには、インストールファイルコマンドを呼び出します:/// 4つのモジュールごとにpath_to_jar_module_file(maven-commandパッケージでモジュールをビルドできます)。 その後、start idコマンドを実行して、API、サービスの1つ、およびクライアントでモジュールを実行します。 テストアプリケーションウィンドウが画面に表示されます。









日付プロデューサーの使用



次に、stop idコマンドでサービスモジュールを停止し、別のサービスを開始します。 更新ボタンをクリックして、ウィンドウのテキストボックスの内容を更新します。









int-producerを使用する



これで、テストケースの説明は完了です。 これは、ジェミニブループリントの機能のほんの一部にすぎないことを強調したいと思います。



応用分野





OSGiは長い間、組み込み技術向けのモジュラーシステムの標準以上のものでした。 上記をサポートするために、EclipseやGlassfishのようなOSGiベースの広範なプロジェクトの例を挙げるだけで十分です。 Spring Frameworkは、エンタープライズ市場で確固たる地位を築いています。 なぜこれらの技術の相乗効果を使用できるのですか? 作成者が考えたこのバンドルの主な適用分野は、企業アプリケーションの分野でした。 実際、これはOSGiを企業の世界に持ち込むための成功した試みです。 そして今、私たちは、Spring Frameworkと連携して、あらゆるエンタープライズアプリケーションやアプリケーションアプリケーションでOSGiを使用する機会を得ています。



短所





動的なモジュール式アーキテクチャには大きな利点がありますが、SpringとOSGiには欠点があります。 最も重要な欠点は、この靭帯の有病率が比較的低いことです。 もちろん、これらの技術は個々に、その存続可能性について疑いを提起しませんが、それらを一緒に使用するユーザーの数はそれほど多くありません。 主観的に、SpringSourceからEclipse Foundationにプロジェクトを転送するプロセスにより、開発が遅れています。 2番目の欠点は、このバンドルを使用するとプロジェクトがさらに複雑になるということです。 そして、これはこれらの技術を使用することの複雑さではなく、サードパーティのライブラリとの互換性の問題、またはOSGiコンテナでそれらを使用することの問題によって追加される複雑さではありません。



OSGiコンテナーでのSpringの使用に関連するプロジェクト





おわりに





この記事は、SpringおよびOSGi共有テクノロジーの紹介として意図したものです。 導入部に関するすべての情報を完全に説明するには、もっと多くの情報が必要になるので、興味のある読者は追加の情報源を独自に研究することをお勧めします。 さらに、この素​​晴らしい技術に関する質問に喜んでお答えします(私の能力の範囲内)。



追加のソース





例付きのアーカイブ

エクリプスジェミニ

Bnd

OSGi仕様

春のフレームワーク

春の動的モジュール

OSGi SpringSourceブログ

動作中のSpring Dynamic Modules

エクリプスバーゴ




All Articles