2009-07-09 9 views
4

Ich beginne gerade mit OSGI und deklarativen Diensten (DS) mit Equinox und Eclipse PDE.OSGI Deklarative Services (DS): Was ist eine gute Möglichkeit, Servicekomponenteninstanzen zu verwenden?

Ich habe 2 Bundles, A und B. Bundle A stellt eine Komponente, die von Bundle B. verbraucht wird Beiden Bundles diesen Service auch auf den wieder Registry OSGi Service aussetzen.

Alles funktioniert gut und Equinox verbindet die Komponenten zusammen, was bedeutet, dass Bundle A und Bundle B durch Equinox (durch Aufruf des Standardkonstruktors) installiert werden und dann die Verbindung mit den Bind/Unbind-Methoden erfolgt.

Nun, da Equinox die Instanzen dieser Komponenten/Dienste erstellt, würde ich gerne wissen, was der beste Weg ist, diese Instanz zu bekommen?

es also davon ausgehen, dritte Klasse Klasse ist, die nicht von OSGi instanziiert wird:

Class WantsToUseComponentB{ 
public void doSomethingWithComponentB(){ 
// how do I get componentB??? Something like this maybe? 
ComponentB component = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName()); 
}

ich jetzt folgende Optionen:



1. Verwenden Sie einen Servicetracker in der Activator, um den Service von ComponentBundleA.class.getName() zu bekommen (Ich habe das bereits versucht und es funktioniert, aber es scheint zu viel Overhead für mich) und es über eine statische Fabrik verfügbar machen

Methoden
 
public class Activator{ 

    private static ServiceTracker componentBServiceTracker; 

    public void start(BundleContext context){ 

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

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

} 

2. Erstellen Sie eine Art von Registry wobei jede Komponente Register, sobald die activate() -Methode aufgerufen wird.

 
public ComponentB{ 

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

oder

 
public ComponentB{ 

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

} 

}

3. Verwenden Sie eine vorhandene Registrierung innerhalb osgi/Tagundnachtgleiche, die diese Instanzen hat? Ich meine, OSGI erstellt bereits Instanzen und verbindet sie miteinander, so dass die Objekte bereits irgendwo vorhanden sind. Aber wo? Wie kann ich sie bekommen?

Fazit Woher kommt die Klasse WantsToUseComponentB (die nicht Bestandteil und nicht die von OSGi instanziiert) erhalten eine Instanz von ComponentB aus? Gibt es Muster oder Best Practices? Wie gesagt, ich habe es geschafft, einen ServiceTracker im Activator zu verwenden, aber ich dachte, das wäre ohne ihn möglich.

Was ich suche, ist eigentlich so etwas wie der BeanContainer von Springframework, wo ich einfach etwas wie Container.getBean (ComponentA.BEAN_NAME) sagen kann. Aber ich möchte Spring DS nicht verwenden.

Ich hoffe, das war klar genug. Ansonsten kann ich auch etwas Quellcode posten, um das genauer zu erklären.

Dank Christoph


AKTUALISIERT: Antwort Neil Kommentar:

Vielen Dank für diese Frage gegen die ursprüngliche Version zu klären, aber ich denke immer noch, warum die angeben müssen Die dritte Klasse kann nicht über etwas wie DS erstellt werden.

Hmm weiß es nicht. Vielleicht gibt es einen Weg, aber ich müsste mein gesamtes Framework so umgestalten, dass es auf DS basiert, sodass es keine "neuen MyThirdClass (arg1, arg2)" - Anweisungen mehr gibt. Ich weiß nicht wirklich, wie ich das machen soll, aber ich habe etwas über ComponentFactories in DS gelesen. Anstatt also einen tun

 
MyThirdClass object = new MyThirdClass(arg1, arg2); 

könnte ich tun, um ein

 
ComponentFactory myThirdClassFactory = myThirdClassServiceTracker.getService(); // returns a 

if (myThirdClassFactory != null){ 
    MyThirdClass object = objectFactory.newInstance(); 

    object.setArg1("arg1"); 
    object.setArg2("arg2"); 
} 
else{ 
// here I can assume that some service of ComponentA or B went away so MyThirdClass Componenent cannot be created as there are missing dependencies? 

} 

Zum Zeitpunkt des Schreibens ich nicht genau wissen, wie die ComponentFactories zu verwenden, aber dies soll eine Art Pseudo-Code sein :)

Dank Christoph

Antwort

5

Christoph,

Vielen Dank für diese Frage gegen die ursprüngliche Version zu klären, aber ich denke, Sie noch angeben müssen, warum die dritte Klasse kann so etwas wie DS nicht über erstellt werden.

DS führt dazu, dass Komponenten als Dienste veröffentlicht werden. Daher besteht die einzige Möglichkeit, eine Komponente von DS zu "bekommen", über die Service-Registry darauf zuzugreifen. Leider kann es schwierig sein, die Service-Registry mithilfe der APIs auf niedrigerer Ebene korrekt zu verwenden, da sie dynamisch ist. Sie müssen also mit der Möglichkeit umgehen, dass Services genau dann verfügbar oder nicht verfügbar sind, wenn sie verfügbar sein sollen . Aus diesem Grund gibt es DS: Es gibt Ihnen eine Abstraktion für die Abhängigkeit von Services und die Verwaltung des Lebenszyklus Ihrer Komponenten basierend auf der Verfügbarkeit von Services, auf die sie verweisen.

Wenn Sie wirklich auf einen Dienst zugreifen müssen, ohne DS oder etwas ähnliches zu verwenden (und es gibt eine ganze Reihe von "Dingen wie", z.Frühlings-DM, iPOJO, Guice/Peaberry, usw.) sollten Sie ServiceTracker verwenden. Ich stimme zu, dass es eine Menge Overhead gibt - deshalb gibt es DS stattdessen.

Um Ihren Vorschlag nein (2), nein zu beantworten, sollten Sie Ihre eigene Registrierung von Diensten nicht erstellen, da die Dienstregistrierung bereits vorhanden ist. Wenn Sie eine separate parallele Registrierung erstellt haben, müssten Sie immer noch mit allen Dynamiken umgehen, aber Sie müssten sie an zwei statt einer Stelle behandeln. Gleiches gilt für den Vorschlag (3).

Ich hoffe, das hilft.

Grüße, Neil

AKTUALISIERT: Übrigens, obwohl Frühling die Container.getBean() Backdoor hat, merkt man, dass es in allen Feder Dokumentation wird dringend empfohlen, nicht, dass die Backdoor zu verwenden: halten einen Frühling zu bekommen Bean, erstellen Sie einfach eine andere Bean, die darauf verweist. Das gleiche gilt für DS, d. H. Der beste Weg, um eine DS-Komponente zu erhalten, besteht darin, eine andere DS-Komponente zu erstellen.

Beachten Sie auch, dass es in der OSGi-Welt, auch wenn Sie Spring-DM verwenden, keinen einfachen Weg gibt, getBean() aufzurufen, weil Sie zuerst den Spring ApplicationContext aufrufen müssen. Das ist selbst ein OSGi-Dienst, also wie bekommt man diesen Dienst?

+0

Danke für deine Antwort Neil. Ok nehme an, die 3. Klasse ist eine Klasse innerhalb meines eigenen Legacy-Frameworks und es gibt ein Objekt, das nicht von DS erstellt werden kann. Ich würde gerne wissen, ob der Weg des statischen ServiceTracker und die statische Fabrikmethode im Activator ein guter Weg ist? Mir scheint es ein bisschen hacky, aber weiß nicht warum. Ich möchte keine statischen ServiceTrackers überall verwenden, aber genau jetzt mache ich es so. Gibt es einen besseren Ansatz? Ich denke, es gibt :) Dank Christoph – Christoph

+0

Hallo Neil, Ich aktualisierte die Fragen erneut (siehe UPDATE am unteren Rand), um Ihre erste Frage zu beantworten. – Christoph

0

christoph, weiß nicht, ob ich das Problem wirklich verstehen. pro ex. Bundle A bietet einen Service mit DS-Komponente:

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

Bundle B erfordert diesen Service DS-Komponente:

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

sobald Bundle A den Service bietet , Bundle "erhält" es durch die bind() -Methode der Implementierungsklasse:

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

hoffe, das hilft ekke

+0

Bündel B erfordert auch den Service (Zeile war nach dem Veröffentlichen meiner Antwort "gegangen") ekkescorner

+0

Danke Ekke für Ihre Antwort: Ich aktualisierte meine Frage mit mehr Details und Codebeispielen. Was mich interessiert, ist eigentlich eine 3. Klasse wie folgt:

Class WantsToUseComponentB{ public void doSomethingWithComponentB(){ // how do I get componentB??? Something like this maybe? ComponentB component = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName()); } 
Könnten Sie noch einmal schauen? Danke Christoph – Christoph

Verwandte Themen