我創建了一個服務有多個實現,就像這樣:如何選擇合適的服務實施?
@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獲得服務的不同實例,但不指定實現。
實際使用案例用於集成測試工具;我正在詢問關於測試不同文件類型正確性的服務實現。非OSGi版本允許測試寫入任意輸出文件並選擇工廠的相應服務實現。如果我們將測試本身轉換爲實現ServiceFactory的服務,那麼我們可以使用Config Admin創建新的測試實例,並使用目標來定義它們的輸出類型(非常肯定我們有這些信息可用)。謝謝 – pconley
因此,在這種情況下,您應該讓知道該類型的服務作出決定。在這種情況下,消費者應該遍歷所有服務並詢問服務是否可以處理文件類型。如果是這樣,它應該進行驗證。如果你不是非常小心,你會發現消費者知道所有可能的文件類型,併成爲一個熱點,因爲每當你添加一個新的文件類型,你需要更新它。 –