我正在Eclipse RCP中开发应用程序。我需要有关服务设计的设计决策方面的帮助。

我有一些捆绑包,用于向其他模块提供REngine对象。 REngine是计算引擎的接口,可以通过多种方式实现。捆绑包通过连接到远程服务器或启动本地计算线程来提供REngine的实例。有些捆绑软件需要通过GUI进行配置(但也需要在无头平台上可用)。客户端捆绑包可以请求多个REngine对象进行并行计算。

我目前正在注册这些模块以提供REngine服务。该服务由ServiceFactory创建,该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对象是 Activity 对象,应该在不再需要它们时将其释放。

但是,一个注册的服务每个捆绑包只能提供一个服务实例。第二次请求该服务时,将返回一个缓存实例(而不是创建一个新实例)。这不符合我的要求;一个包应该能够从同一个提供者那里获取多个REngine对象。

我已经看过其他OSGi框架类,但似乎无济于事。另一种选择是白板模型,但是注册由REngineProvider捆绑包使用的REngineRequestService发出实时REngine似乎很奇怪。

如何在OSGi中实现呢?提醒一下,这是我的要求列表:
  • 轻松启用和禁用REngineProvider捆绑包。客户端代码将只使用另一个提供程序。
  • REngineProvider捆绑软件的配置。
  • 每个客户端捆绑包有多个REngine实例。
  • 明确发布REngine实例
  • REngine创建可能失败。客户端模块应该能够知道原因。


  • 只是添加我选择作为将来参考的解决方案。似乎OSGi服务平台不是为“请求服务”而设计的。创建服务的是提供者捆绑包,可以找到和使用服务的是客户端捆绑包。无法根据用户请求为服务提供自动的“工厂”。

    选择的解决方案涉及OSGi whiteboard model。乍一看,这似乎很难管理,但是Blueprint可以提供很大帮助!

    提供程序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对象,或设置一个Exception来解释创建失败的原因。

    对于客户端,使用REngine现在变得很容易:
    REngineRequest req = new REngineRequest();
    ServiceRegistration reg = bundleContext.registerService(req, REngineRequest.class.getName(), engineCreationProperties);
    req.getEngine().doSomeStuff();
    reg.unregister();
    

    我们假设客户端在使用REngine时提供者永远不会停止。如果是这样,则REngine无效。

    最佳答案

    您需要的是ComponentFactory中的Declarative Services。大多数情况下,您应该使用DS而不是手动注册和查找服务。

    提供方应注册REngine工厂服务(您不必自己实施工厂,DS会为您完成)。结束者应该声明对REngine服务的一对多依赖性。在运行时,将注入所有可用的工厂,并且消费者可以遍历它们来创建实际的REngine实例。

    08-06 16:12