繁体   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