6

EquinoxとEclipsePDEを使用してOSGIと宣言型サービス(DS)を使い始めたところです。

AとBの2つのバンドルがあります。バンドルAは、バンドルBによって消費されるコンポーネントを公開します。どちらのバンドルも、このサービスをOSGIサービスレジストリに再度公開します。

これまでのところすべてが正常に機能しており、Equinoxはコンポーネントを相互にワイヤリングしています。つまり、バンドルAとバンドルBは(デフォルトのコンストラクタを呼び出すことによって)Equinoxによってインスタンス化され、バインド/アンバインドメソッドを使用してワイヤリングが行われます。

さて、Equinoxがそれらのコンポーネント/サービスのインスタンスを作成しているので、このインスタンスを取得するための最良の方法を知りたいですか?

したがって、OSGIによってインスタンス化されないサードクラスのクラスがあると仮定します。

クラスWantsToUseComponentB{
public void doSomethingWithComponentB(){
 // componentBを取得するにはどうすればよいですか?多分このような何か?
 ComponentBコンポーネント=(ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName());
}

現在、次のオプションが表示されています。



1. ActivatorでServiceTrackerを使用してComponentBundleA.class.getName()のサービスを取得し(すでに試しましたが、機能しますが、かなりのオーバーヘッドがあるようです)、静的ファクトリメソッドを介して利用できるようにします。

 
パブリッククラスアクティベーター{

   プライベート静的ServiceTrackercomponentBServiceTracker;   

   public void start(BundleContext context){

     componentBServiceTracker = new ServiceTracker(context、ComponentB.class.getName()、null);
   }

   public static ComponentB getComponentB(){
     return(ComponentB)componentBServiceTracker.getService();
   };

}

2. activate()メソッドが呼び出されるとすぐに各コンポーネントが登録される、ある種のレジストリを作成します。

public ComponentB {

public void bind(ComponentA componentA){
   someRegistry.registerComponent(this);
}

また

public ComponentB {

   public void activate(ComponentContext context){
      someRegistry.registerComponent(this);
   }

}

}

3.それらのインスタンスを持つosgi/equinox内の既存のレジストリを使用しますか?つまり、OSGIはすでにインスタンスを作成し、それらを相互に接続しているので、オブジェクトはすでにどこかにあります。しかしここで?どうすれば入手できますか?

結論 クラスWantsToUseComponentB(これはコンポーネントではなく、OSGIによってインスタンス化されません)はどこからComponentBのインスタンスを取得しますか?パターンやベストプラクティスはありますか?先ほど言ったように、ActivatorでServiceTrackerを使用することができましたが、それがなくても可能だと思いました。

私が探しているのは、実際にはSpringframeworkのBeanContainerのようなもので、Container.getBean(ComponentA.BEAN_NAME)のようなものを言うことができます。しかし、私はSpringDSを使いたくありません。

それが十分に明確だったことを願っています。それ以外の場合は、ソースコードを投稿して詳細を説明することもできます。

ありがとうクリストフ


更新: ニールのコメントへの回答:

元のバージョンに対してこの質問を明確にしていただきありがとうございますが、DSなどを使用して3番目のクラスを作成できない理由を説明する必要があると思います。

うーん、わかりません。方法はあるかもしれませんが、フレームワーク全体をリファクタリングしてDSに基づくようにし、「new MyThirdClass(arg1、arg2)」ステートメントがなくなるようにする必要があります。その方法はよくわかりませんが、DSのComponentFactoriesについて何か読んでいます。だから、する代わりに

MyThirdClassオブジェクト=newMyThirdClass(arg1、arg2);

私はするかもしれません

ComponentFactory myThirdClassFactory = myThirdClassServiceTracker.getService(); //を返します

if(myThirdClassFactory!= null){
  MyThirdClassオブジェクト=objectFactory.newInstance();

   object.setArg1( "arg1");
  object.setArg2( "arg2");
}
そうしないと{
 //ここでは、ComponentAまたはBの一部のサービスが停止したため、依存関係が欠落しているためMyThirdClassコンポーネントを作成できないと想定できますか?

}

これを書いている時点では、ComponentFactoriesの使用方法は正確にはわかりませんが、これはある種の擬似コードであると思われます:)

ありがとうクリストフ

4

3 に答える 3

7

クリストフ、

元のバージョンに対してこの質問を明確にしていただきありがとうございますが、DSなどを使用して3番目のクラスを作成できない理由を説明する必要があると思います。

DSを使用すると、コンポーネントがサービスとして公開されるため、DSからコンポーネントを「取得」する唯一の方法は、サービスレジストリを介してコンポーネントにアクセスすることです。残念ながら、サービスレジストリは動的であるため、低レベルのAPIを使用して正しく使用するのは難しい場合があります。そのため、サービスを利用可能にしたいときに、サービスが停止したり利用できなくなったりする可能性に対処する必要があります。 。これがDSが存在する理由です。DSは、サービスに依存し、参照するサービスの可用性に基づいてコンポーネントのライフサイクルを管理するための抽象化を提供します。

DSなどを使用せずにサービスにアクセスする必要がある場合(Spring-DM、iPOJO、Guice / Peaberryなどの「そのようなもの」の選択肢がかなりある場合)、ServiceTrackerを使用する必要があります。私は多くのオーバーヘッドがあることに同意します-繰り返しますが、これが代わりにDSが存在する理由です。

いいえ(2)の提案に答えるには、サービスレジストリがすでに存在するため、独自のサービスレジストリを作成しないでください。別の並列レジストリを作成した場合でも、すべてのダイナミクスを処理する必要がありますが、1つではなく2つの場所で処理する必要があります。同じことが提案(3)にも当てはまります。

これがお役に立てば幸いです。

よろしく、ニール

更新:ちなみに、SpringにはContainer.getBean()バックドアがありますが、すべてのSpringドキュメントでは、そのバックドアを使用しないことを強くお勧めします。SpringBeanを入手するには、それを参照する別のBeanを作成するだけです。同じことがDSにも当てはまります。つまり、DSコンポーネントを入手する最良の方法は、別のDSコンポーネントを作成することです。

また、OSGiの世界では、Spring-DMを使用している場合でも、最初にSpring ApplicationContextを取得する必要があるため、getBean()を呼び出す簡単な方法はありません。それ自体がOSGiサービスですが、どのようにしてそのサービスを利用できますか?

于 2009-07-09T11:21:39.797 に答える
1

クリストフ、私があなたの問題を本当に理解しているかどうかわからない。例ごと バンドルAは、DSコンポーネントを使用してサービスを提供しています。

<service>
  <provide interface="org.redview.lnf.services.IRedviewLnfSelectedService"/>

バンドルBには、DSコンポーネントを使用した次のサービスが必要です。

<implementation class="ekke.xyz.rcp.application.internal.XyzApplicationLnfComponent"/>

バンドルAがサービスを提供するとすぐに、バンドルBは実装クラスのbind()メソッドを介してサービスを「取得」します。

public class XyzApplicationLnfComponent {
public void bind(IRedviewLnfSelectedService lnfSelectedService) {
    // here it is
}

これがekkeに役立つことを願っています

于 2009-07-09T10:39:37.107 に答える
0

簡単な方法:Rienaを使用してDSコンポーネントをActivatorクラスに注入します: http ://wiki.eclipse.org/Riena_Getting_Started_with_injecting_services_and_extensions

次に、どこからでも呼び出すことができます:Activator.getDefault()。getWhateverService()

于 2010-05-10T21:24:52.363 に答える