簡體   English   中英

如何為 OSGi 服務創建代理

[英]How To Create Proxy For OSGi Service

假設我有一個非常簡單的界面來從某個地方獲取文件:

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 中創建代理?

為另一個服務定義代理的更安全方法是使用服務屬性。 例如,您可以為慢速 FileManager 提供一個類似“name=A”的屬性。

然后你可以給代理屬性 name=A,cached=true。 在初始化時,您可以給代理一個過濾器 name=A 來搜索要代理的服務。

因此,如果服務的用戶需要緩存的變體,則該服務的用戶可以使用任何服務(通過排名)或過濾 cached=true。

為什么不創建一個服務來收集其他服務的注冊實現呢? 示例實現和您可以從這里獲得的想法。

我認為您所描述的是一種 2 服務模型,因為您結合了多種職責。 您將緩存責任與文件來源的抽象結合起來。 或者換句話說,您的設計混合了關注點,因此沒有凝聚力

因此,最簡單的解決方案是擁有一個FileManager和一個FileManagerProvider服務。 然后,您可以根據您的情況提供緩存文件管理器和透明文件管理器。

35 多年前,當我開始從事軟件工作時,我得到了耦合,但我花了很多年才明白內聚的重要性。 這個問題是一個非常典型的例子。

現在要了解為什么這種設計很糟糕,您可以使用 OSGi 服務掛鈎來實現代理。 您注冊替代服務並隱藏原始服務。 然而,制作技術劣質解決方案需要大量工作,因為所有與代理相關的解決方案都有其自身的問題。 保持簡單、直接並使用實際類型來表示您的抽象是最好的解決方案。 (雖然我承認我經常發現在我很好地理解問題之前,我最初也做出了不連貫的設計。)

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();
     }
 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM