2016-04-22 10 views
1

のは、私がどこかからファイルを取得するための本当にシンプルなインターフェイスを持っているとしましょう:のOSGiサービスのプロキシを作成する方法を

interface FileManager { 

    File getFile(Object data); 
} 
我々がこのインタフェースの複数の実装があり、すべてのアプリケーションが唯一のインターフェイスを使用していると仮定することができます

OSGiのコンテキストにどのような実装が提供されているかは、幸せには分かりません。

ファイルを取得するいくつかの方法が実際には遅いため、オプションのキャッシュを追加します。しかし、私はアプリケーションがFileManagerインタフェースから別のインタフェースに変更されることを望んでいません。それは、アプリケーションがどの実装を使用しているか(そして遅いかどうか)を認識させるからです。

だから私はこの思い付いた:

class FileManagerCache implements FileManager { 

private final Map<Object, File> cache = new HashMap<>(); 

public File getFile(final Object data) { 
    if (this.cache.containsKey(data)) { 
     return this.cache.get(data); 
    } 
    final File result = getDelegate().getFile(data); 
    this.cache.put(data, result); 
    return result; 
} 

private FileManager getDelegate() { 
    for (final FileManager fileManager : ServiceUtil.findServices(FileManager.class)) { 
     if (this != fileManager) { 
      return fileManager; 
     } 
    } 
    throw new UnsupportedOperationException("No FileManager is present!"); //$NON-NLS-1$ 
} 
} 

この実装は可能なのリストに並んでいる次のいずれかに非常に高い"service.ranking"に登録し、そのアプリケーションが使用する最初のもの、それは委譲しています実装。

このアプローチは非常にエレガントではなく、おそらくエラーが発生する可能性があります。標準的なメカニズムを使ってOSGiでプロキシを作成するには?

答えて

1

他のサービスのプロキシをより安全に定義する方法は、サービスプロパティを使用することです。 たとえば、低速のFileManagerに「name = A」のようなプロパティを与えることができます。

次に、プロキシにpropertie name = A、cached = trueを指定できます。初期化時に、プロキシにフィルタ名= Aを付けると、プロキシへのサービスを検索できます。

したがって、キャッシュされたバリアントが必要なサービスのユーザーは、任意のサービス(ランク付け)またはフィルタを使用できます。

+0

これはまだ彼が取得するどの実装を知る方法はありません、呼び出し元に使用するサービスを決定する責任をプッシュします。これは複数の実装が遅い場合でも実際には機能しません。 –

+0

少なくとも、宣言型サービスの場合、構成内のサービス参照のフィルタをカスタマイズできます。だから、それはユーザーによって決めることができます。または、完全に自動化されたシステムを使いたいですか? –

+0

私の質問は、未知の他の実装に委任しながら、サービスインタフェースの実装として機能するプロキシを作成する方法についての詳細です。 –

0

他のサービスの登録済み実装を収集するサービスを作成するだけではどうですか?実装の例とhereから得ることができるアイデア。

+0

これは私が今やっていることとどのように違うのですか?実行時にすべての実装を取得する(「すべて」はゼロまたは1つのサービスです)、そのうちの1つに委譲しますか? –

+0

異なる方法で自分自身を初期化する必要はなく、その特定のインターフェースを使用してOSGiサービスとして登録するだけです(OSGiの標準メカニズムを頼んでいます)。特定のクライアント/ファイルマネージャを使用するファイルサービスよりも、あなたが実装したいのは、次のようにバインドできます: '@Reference(target ="(service.config-id = cachablefilemanager) ") private FileManager fileManager ; ' – d33t

+0

私は今OSGiサービスとして実装を登録しています。そして、私は** FileManagerのユーザが彼がどのような実装を行うのか知っていなければならない**を避けたいです。また、キャッシュされるかどうかを判断するには、FileManagerを修飾する必要があるかどうかを知る必要があります。 –

0

複数の責任を組み合わせるため、2つのサービスモデルが記述されていると思います。キャッシングの責任は、ファイルがどこから来たのかを抽象化することによって決まります。言い換えれば、あなたのデザインは心配しているので、粘着性のではありません。

したがって、最も簡単な解決策は、FileManagerFileManagerProviderサービスを持つことです。状況に応じて、キャッシュされたファイルマネージャと透過的なファイルマネージャを提供することができます。

私が35年以上前にソフトウェアで起動したとき、私はカップルを持っていましたが、どれだけ重要な結束があるかを理解するまでには長年かかりました。この問題は非常に典型的な例です。

なぜこのデザインが悪いのかを知るために、OSGiサービスフックでプロキシを実装できます。代替案を登録し、元のサービスを非表示にします。しかし、プロキシ関連のソリューションにはそれぞれ独自の問題があるため、それは技術的に劣ったソリューションを作るための多くの作業です。それを単純明快に保ち、実際の型を使用して抽象を表現するのが最良の解決策です。 (私がよく問題をよく理解する前に、もともと不協和音的なデザインをしていたことがよく分かりますが)。

0

Felix DependencyManagerがサポートしています。http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/reference/component-aspect.html

依存性マネージャから要約あり

- アスペクト

態様は、アスペクト指向プログラミングの一部として、「伸びる」するためにそのようなOSGiのよう 動的環境で使用することができます既存のサービスに追加し、 を追加してください。これらの例としては、ストレージサービスに 固有のキャッシングメカニズムを追加するか、またはログを実装する( )ことです。 OSGiの側面はサービスに適用することができ、実行時に を追加して削除することができます。

アスペクトを使用すると、サービスにキャッシングやロギングなどの機能を追加するためのインターセプタまたはインターセプタチェーンを定義できます。アスペクトは、指定されたインターフェイスとフィルタに一致するすべてのサービスに適用されます。一致するサービスごとに、アスペクト実装クラスに基づいてアスペクトが作成されます。このアスペクトは、元のサービスと同じインターフェイスとプロパティ、およびここで指定した追加のプロパティで登録されます。また、すべての依存関係を継承し、元のサービスをメンバーとして宣言すると、そのサービスはインジェクトされます。

@AspectService(ranking=10), properties={@Property(name="param", value="value")}) 
class AspectService implements InterceptedService { 
    // The service we are intercepting (injected by reflection) 
    protected InterceptedService intercepted; 

    public void doWork() { 
     intercepted.doWork(); 
    } 
} 
関連する問題