OSGi服务架构:根据消费者的要求创建服务

时间:2012-03-28 11:52:52

标签: java eclipse-rcp osgi

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

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

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

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

我已经查看了其他OSGi框架类,但似乎没有任何帮助。另一种选择是白板模型,但是注册REngineRequest服务并使用REngineProvider包来提供实时REngine似乎很奇怪。

如何在OSGi中实现此功能?提醒一下,这是我的要求清单:

  1. 轻松启用和禁用REngineProvider个捆绑包。客户端代码将改为使用其他提供商。
  2. 配置REngineProvider捆绑包。
  3. 每个客户端捆绑包有多个REngine个实例。
  4. 明确释放REngine个实例
  5. REngine创建可能会失败。客户端模块应该能够知道原因。

  6. 只需添加我选择的解决方案作为未来参考。似乎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变为无效。

3 个答案:

答案 0 :(得分:3)

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

供应商方应注册REngine工厂服务(您不必自己实施工厂,DS会为您执行此操作)。构造者应该声明对REngine服务的一对多依赖。在运行时,将注入所有可用的工厂,并且消费者可以通过它们来创建实际的REngine实例。

答案 1 :(得分:3)

两年前,我尝试创建真正的服务工厂,后来成为参数化服务。然而,经过分析后发现不需要任何东西,只需将工厂注册为服务。

然而

我对你的服务知之甚少,但听起来你可以通过从客户端包中删除控制来大大简化事情,客户端包应该只使用服务注册表中可用的任何REngine服务,也许是属性如果有多个捆绑包需要REngines并且它们不应共享相同的REngine(很少应该是这种情况),则表示其使用类型。

如果可以使用该模型,通常会大大简化。我通常会使用带有驱动实例的配置管理配置的DS(DS最有用的方面之一,请参阅http://www.aqute.biz/Bnd/Components)。通过元类型集成,您甚至可以获得用户界面来编辑配置属性。

答案 2 :(得分:1)

一种解决方案是将REngineFactory注册为服务而不是REngine实现本身,并从getService方法返回工厂。通过这种方式,客户可以查找工厂,并在成功找到工厂后,使用它来获得新的REngine实现。