2012-03-28 62 views
5

我正在Eclipse RCP中開發應用程序。我需要關於服務設計的設計決定方面的幫助。OSGi服務體系結構:根據消費者的要求創建服務

我有一些捆綁被用來提供一個REngine對象到其他模塊。 REngine是計算引擎的接口,可以通過多種方式實現。這些軟件包通過連接到遠程服務器或啓動本地計算線程來提供REngine的實例。某些軟件包需要通過GUI進行配置(但也需要在無人平臺上提供)。客戶端Bundle可以請求多個REngine對象進行並行計算。

我目前註冊這些模塊以提供REngine服務。該服務由ServiceFactory創建,該服務啓動本地計算實例或遠程(服務器)實例。客戶負責嘗試REngine課程的所有服務註冊並選擇正確的課程。

class API.REngine { ... } 

class REngineProvider.Activator { 
    public void start(BundleContext ctx) { 
     ctx.registerService(REngine.class.getName(), new REngineFactory(), null); 
    } 
} 
class REngineProvider.REngineFactory implements ServiceFactory { 
    public Object getService(Bundle bundle, ServiceReference reference) { 
     return new MyREngineImplementation(); 
    } 
    public void ungetService(REngine service) { 
     service.releaseAssociatedResources(); 
    } 
} 

class RConsumer.Class { 
    REngine getREngine() { 
     ServiceReference[] references = bundleContext.getAllServiceReferences(REngine.class.getName(), null); 
     for(ServiceReference ref: references) { 
      try { 
      return bundleContext.getService(ref); 
      } catch (Exception e) {} // too bad, try the next one 
     } 
    } 
} 

我想保持這種模式:

做到這一點的代碼可以總結如下。很高興OSGi服務規範符合我的業務要求,即REngine對象是在不再需要時應該釋放的活動對象。

但是,註冊的服務只能爲每個包提供一個服務實例。第二次請求服務時,將返回一個緩存實例(而不是創建一個新實例)。這與我的要求不符。一個bundle應該能夠從同一個提供者獲得多個REngine對象。

我已經看過其他OSGi框架類,但似乎沒有任何幫助。另一種方法是白板模式,但註冊REngineProvider軟件包使用的REngineRequestService來發出實時REngine似乎很奇怪。

如何在OSGi中實現這個功能?提醒一下,這裏是我的要求列表:

  1. 易於啓用和禁用REngineProvider捆綁軟件。客戶端代碼將只使用另一個提供者。
  2. 配置REngineProvider包。
  3. 每個客戶端軟件包多個REngine實例。
  4. 顯式發佈的REngine實例
  5. REngine創建失敗。客戶端模塊應該能夠知道原因。

我想補充我選擇作爲未來的參考解決方案。看來OSGi服務平臺不是用於「請求服務」。它是創建服務的提供程序包,以及可以找到並使用服務的客戶端包。無法爲每個用戶的請求提供服務的自動「工廠」。

所選解決方案涉及OSGi whiteboard model。一見鍾情,這似乎很難管理,但Blueprint可以幫助很多!

供應商藍圖。xml文件:

<reference-list interface="org.application.REngineRequest" 
      availability="optional"> 
    <reference-listener 
      bind-method="bind" unbind-method="unbind"> 
     <bean class="org.provider.REngineProvider"/>   
    </reference-listener> 

REngineRequest是一個共享的API類,允許供應商輸入他REngine對象,或設置例外解釋爲什麼創作沒有工作。

對於客戶端,使用REngine現在是那麼容易,因爲這樣做的:

REngineRequest req = new REngineRequest(); 
ServiceRegistration reg = bundleContext.registerService(req, REngineRequest.class.getName(), engineCreationProperties); 
req.getEngine().doSomeStuff(); 
reg.unregister(); 

我們作一個假設,當客戶端使用REngine提供商將永遠不會停止。如果是這樣,REngine將無效。

回答

3

ComponentFactoryDeclarative Services是你所需要的。大多數情況下,您應該使用DS而不是手動註冊和查找服務。

服務提供方應註冊REngine工廠服務(您不必自行實施工廠,DS會爲您服務)。 Consmer應該向REngine服務聲明一對多的依賴關係。在運行時,所有可用的工廠將被注入,並且消費者可以通過它們來創建實際的REngine實例。

+0

您會推薦使用BluePrint和PROTOTYPE批註代替DS嗎?我很難看出差異。 – parasietje 2012-03-28 15:47:48

+0

我正在建議藍圖和原型範圍。藍圖擁有比聲明式服務更多的旋鈕,這可能對您有用。 – 2012-03-28 16:16:29

+0

不幸的是,我創建我的對象時需要上下文(屬性)。我不能指定一個簡單的工廠方法,但必須指定一個實例化的類。讓我們希望藍圖有這樣的東西! – parasietje 2012-03-28 18:04:29

1

一種解決方案是將REngineFactory註冊爲服務而不是REngine實現本身,並從getService方法返回工廠。這樣客戶可以查找工廠,並在成功找到工廠時使用它來獲得新的REngine實施。

3

兩年前,我試圖創建後來成爲參數化服務的Genuine Service Factories。然而,經過分析後發現沒有必要,只需將工廠註冊爲服務即可。

但是,

我對你的服務不夠了解,但是聽起來你可以通過從客戶端軟件包中刪除控制來顯着簡化一些事情,客戶端軟件包應該只使用服務註冊表中可用的任何REngine服務,如果有多個需要REngine的bundle並且它們不應該共享相同的REngine(應該很少出現這種情況),那麼該屬性將指示其使用類型。

如果這個模型是可能的,它通常會大大簡化。我通常會使用帶有配置管理配置的DS來驅動實例(DS中最有用的一個方面,請參閱http://www.aqute.biz/Bnd/Components)。通過元類型集成,您甚至可以獲得用戶界面來編輯您的配置屬性。

+0

這可能是最簡單的實現。獲得服務的軟件包將觸發新服務的註冊。 – parasietje 2012-04-02 10:29:53

+0

啊哈!因此,解決方案是使用配置管理員提供「我希望您創建以下REngine實例」列表,然後獲取服務。我可以通過發佈異常而不是REngine對象本身來傳達異常。剩下的問題是請求服務和獲得服務之間的時間問題。 – parasietje 2012-04-02 10:33:57

+2

獲取服務不會觸發新的註冊。有兩個步驟:客戶端軟件包接受註冊表中的所有內容,配置管理員定義通過DS組件提供的內容。使用DS組件,您可以表達您的依賴關係,因此無需擔心時間安排問題。除非你是一些中間件開發者,否則不要使用ServiceReferences ... DS非常乾淨,尤其是註釋 – 2012-04-02 10:57:35