3

これは別の質問の複製ですが、他の質問からコピーしています:

Felix SCR で次のメッセージが表示される問題に遭遇しました。

ServiceFactory.getService() で循環が発生しました

これが発生する理由は、アクティブ化メソッド内でそれを ServiceAImpl (ServiceA を提供する) と呼び、サービスが別のサービスを登録し、それを ServiceB と呼ぶためです。

ServiceA と ServiceB の両方に依存する ServiceCImpl という別のサービス コンポーネントがあります。ServiceAImpl が ServiceB を登録することで、ServiceCImpl が成立し、ServiceAImpl を起動する同じ呼び出し内で、ServiceCImpl バインド メソッドが呼び出されます。ServiceA のバインディング メソッドが呼び出されると、サイクルが検出され、コンポーネントの初期化に失敗します。

SCR が ServiceCImpl をバインドするのを待機できるようにする方法があるのか​​もしれませんし、ServiceB を別の方法で登録する必要があるのか​​もしれません。

Felix SCR が ServiceAImpl のアクティベーション メソッド内で ServiceCImpl をアクティベートする理由が理解できないと思います。アクティベーション メソッドが終了するまで ServiceCImpl が満足しているとは考えられません。おそらくこれは、サービスをフレームワークに直接登録しながら宣言型サービスを使用することの問題でしょうか?

Equinox のバージョンのような他の SCR 実装を試したことはありませんが、違いがあるかどうかを確認するために試してみるかもしれませんが、これが OSGi のものなのか Felix のものなのか誰かが知っているでしょうか?

追加情報: ServiceB がサービス コンポーネントではない理由については、ServiceA には実際には別のサービスに対する 0..n のサービス参照があり、それを ServiceD と呼びます。コンポーネントによって ServiceD インターフェイスが提供されるたびに、同じサービス オブジェクトを使用して ServiceB が登録されます。通常、ServiceD の同じプロバイダーが ServiceB を提供できますが、開発者が複数のサービス インターフェイスを提供する必要がないように、全体的なインターフェイスをより単純化することが目的です (また、ServiceB には、自動的に設定される必要があるいくつかのプロパティがあります)。手動で行われ、間違って行われる可能性があります)。

4

2 に答える 2

2

これが発生しているように見える理由は、ServiceAImpl が既にロードされている遅延コンポーネントであるため、ServiceA は実際にはコンポーネントがアクティブ化される前にすでに登録されているためです。ただし、ServiceA を必要とする別のコンポーネントが出現すると、ServiceAImpl がアクティブになります。ServiceAImpl のアクティベーション プロセスの一部として ServiceB を登録すると、すぐに ServiceCImpl がアクティベートされます。FELIX-2368 では、ほとんどの SCR 操作を同期させることでコンポーネントをすぐにアクティブ化する変更が加えられました。

回避策は、ServiceAImpl を即時コンポーネントにすることです。これは、サービスを必要とするものが何もない場合はアクティブ化されるべきではないため、望ましくありません。この場合、コンポーネントがロードされたときにアクティブ化メソッドが完了し、それが必要になって別のコンポーネントにバインドされるまでには問題ありません。

于 2011-04-22T13:37:14.053 に答える
0

小さなテストバンドルのセットとProSystOSGiFWを使用して、このシナリオを再現しようとしました。ただし、DSにサービスを登録すると、activate()メソッド内から他のサービスを登録できなくなります。DSを使用してサービスを取得するだけで、通常どおりサービスを登録できます。したがって、DS/SCRにはおそらく本当に問題があります...

例:

public class ServiceAImpl implements ServiceA, ServiceB, ManagedService {

public void activate(ComponentContext _context) {
    _context.getBundleContext().registerService(
            ManagedService.class.getName(),
            this,
            null);
    _context.getBundleContext().registerService(
            ServiceB.class.getName(),
            this,
            null);
}


@Override
public void doA() {
    System.out.println("Doing A Stuff");

}


@Override
public void doB() {
    System.out.println("Doing B Stuff");
}


@Override
public void updated(Dictionary arg0) throws ConfigurationException {

}

このクラスは、2つのサービス(ServiceB、ManagedService)をこのbndに登録します。ファイル:

Private-Package: org.test.impl
Service-Component: org.test.impl.ServiceAImpl
Bundle-Category: test

ただし、このサンプルでは1つのサービス(ServiceA)のみです:#

Private-Package: org.test.impl
Service-Component: org.test.impl.ServiceAImpl;provide:=org.test.ServiceA
Bundle-Category: test

したがって、おそらく、DS / SCRを介して、またはバンドルコンテキストを介して「従来の方法」でサービスを登録する必要があります。

于 2011-04-21T12:19:09.783 に答える