2016-08-17 18 views
1

我創建了一個服務有多個實現,就像這樣:如何選擇合適的服務實施?

@ProviderType 
public interface MyService { 
    public void printMessage(); 
} 

@Component 
public class Foo implements MyService { 
    public void printMessage() { 
     System.out.println("foo"); 
    } 
} 

@Component 
public class Bar implements MyService { 
    public void printMessage() { 
     System.out.println("bar"); 
    } 
} 

真正的實現就顯得比較複雜一點(我不能只是做一個單一的實現方式,其中printMessage需要一個說法!)。服務的消費者需要能夠根據屬性選擇適當的實現 - 爲了簡單起見,我們可以假設我使用實現的名稱。

由現有的非OSGi實現中使用的工廠方法是這樣的:

public MyService getService(String property) { 
    switch (property) { 
     case "ham": 
      return new Foo(); 
     case "spam": 
      return new Bar(); 
    } 
} 

真正的實現,同樣,更復雜的(它是基於該property參數的字符串匹配)。最簡單的方法(對我來說)將其轉換爲OSGi將使此工廠方法成爲MyService的靜態方法,僅返回必要的過濾器字符串,並使消費者通過獲取BundleContext來處理繁瑣的位,然後獲取和ungetting服務:

public class MyConsumer { 
    private BundleContext context; 

    @Activate 
    public void activate(BundleContext context) { 
     this.context = context; 
    } 

    public void doStuff() { 
     Collection<ServiceReference<MyService>> refs = context.getServiceReferences(MyService.class, MyService.getService("ham")); 
     ServiceReference<MyService> service = refs.iterator().next(); 
     context.getService(service).printMessage(); 
     context.ungetService(service); 
    } 

有沒有更好的方式來創建一個「工廠」,返回「服務」,但並不要求消費者處理BundleContexts等?

我發現一對夫婦的做法,不會相當工作:

  • @Reference(target = "ham")(我知道,語法錯誤)可以讓我選擇一個基於屬性的實現,但只有在編譯時間。
  • A ServiceFactory允許不同的bundle獲得服務的不同實例,但不指定實現。

回答

2

服務的想法是,消費者不應該選擇,因爲這使得消費者非常不可重用。如果您將該控件移動到消費者中,它通常會形成脆弱的系統。消費者應該使用任何已註冊的內容。

一種反模式是,您試圖隱藏服務的實現,但需要在您的客戶中使用特定的實現。如果這是您的用例,那麼您的實現是公開的,並且只是將其設爲自己的服務類型。它仍然可以註冊爲常見的MyService類型,當然,您可以註冊爲多種類型。

如果您有一個外部選擇標準供哪一個人使用,例如一臺打印機,並且您想要用戶決定,那麼您只需將所有內容顯示給用戶。使用服務ID您可以使用正確的。

如果您需要配置應該使用哪種服務,那麼您應該使用@Reference(target="(selection.criterium=foo)")。您可以使用配置管理覆蓋此選擇。這在targets中有解釋。您基本上將一個屬性設置爲參考名稱,然後是.target到所需的過濾器。

+0

實際使用案例用於集成測試工具;我正在詢問關於測試不同文件類型正確性的服務實現。非OSGi版本允許測試寫入任意輸出文件並選擇工廠的相應服務實現。如果我們將測試本身轉換爲實現ServiceFactory的服務,那麼我們可以使用Config Admin創建新的測試實例,並使用目標來定義它們的輸出類型(非常肯定我們有這些信息可用)。謝謝 – pconley

+0

因此,在這種情況下,您應該讓知道該類型的服務作出決定。在這種情況下,消費者應該遍歷所有服務並詢問服務是否可以處理文件類型。如果是這樣,它應該進行驗證。如果你不是非常小心,你會發現消費者知道所有可能的文件類型,併成爲一個熱點,因爲每當你添加一個新的文件類型,你需要更新它。 –