Osgi ServiceTracker没有';找不到现有的服务

Osgi ServiceTracker没有';找不到现有的服务,osgi,Osgi,我使用ServiceTracker在我们的OSGi环境中定位已注册的服务。 我在Bundle Activator启动方法中获得了以下代码: logger.debug("looking for MyService"); tracker = new ServiceTracker(ctx, MyService.class.getName(), null); tracker.open(); MyService = ((MyService)tracker.getServic

我使用ServiceTracker在我们的OSGi环境中定位已注册的服务。 我在Bundle Activator启动方法中获得了以下代码:

    logger.debug("looking for MyService");
    tracker = new ServiceTracker(ctx, MyService.class.getName(), null);
    tracker.open();
    MyService = ((MyService)tracker.getService());
    if (MyService != null)
    {
        logger.debug("found MyService");
    }
问题是:

  • 如果我安装并启动捆绑包 可以找到并使用服务
  • 如果我完全重新启动OSGi,MyService将无法运行 由我的bundle找到(即为NULL),即使 我的包处于活动状态
  • 如果我停止/启动我的bundle MyService 可以找到并再次使用
我认为问题不在于托管MyService的bundle,因为它显然在那里,如果重新启动bundle,可以再次找到它

看起来我的bundle比包含依赖服务的bundle先加载,这就是为什么它在重新启动后找不到它,而在我重新启动bundle后可以找到它

这表明,如果我使用

ServiceReference[] ref = tracker.getServiceReferences();
在OSGi重启后,它找不到任何服务,但在我停止/启动寻找MyService的捆绑包后,它确实找到了MyService

我试图将requirebundle引用设置为托管MyService的Bundle,希望OSGi框架能够识别依赖关系,但没有帮助


有什么想法吗?

如果使用
BundleActivator
中的
ServiceTracker
,可以有效地冻结整个框架(因此,不能同时启动其他捆绑包)。如果提供您服务的捆绑包在带有跟踪器的捆绑包之后启动,您将看不到该服务。这就解释了为什么稍后停止和启动捆绑包可以为您提供服务


现在,如果您想跟踪和使用该服务,我将生成一个新线程来执行此操作,并使用
waitForService
代替
getService
,您使用ServiceTracker做的事情是正确的。但问题在于,希望被跟踪的服务在activator中可用。您不希望在启动捆绑包和注册服务的捆绑包之间建立排序约束。除非您真的需要在activator的start方法中使用服务(您可能不应该这样做),否则您只需在以后实际需要时获取服务即可


另一个想法是考虑使用声明性服务来管理服务依赖性。

服务在OSGi中非常不稳定,因此当您需要它时,不要期望它在那里,或者在您得到它之后留在那里。这就是为什么您的bundle应该让自己异步收到服务通知的原因

ServiceTracker
类接受一个
ServiceTrackerCustomizer
(它本身就是一个),当服务出现和消失时会收到通知

大多数情况下,使用服务跟踪器的正确方法如下:

// In BundleActivator.start:
this.serviceTracker = new ServiceTracker(bundleContext, MyService.class.getName(), null) {
    public Object addingService(ServiceReference reference) {
        // Get the service
        final MyService service = (MyService)this.context.getService(reference);

        // Do something with the service (e.g. inject it somewhere)
        // ...

        // Return the service to track it
        return service;
    }

    public void removedService(ServiceReference reference, Object service) {
        // Stop using the service (e.g. notify the objects that use it)
        // ...

        // Unget the service (very important!)
        this.context.unget(reference);
    }
}
请注意,我们只跟踪
MyService
服务,不使用任何定制器(我们将
null
作为第三个参数传递给构造函数),而是覆盖这两个重要方法。另一个重要的方法是
modifiedService
;请阅读Javadoc以了解更多信息


管理这很快会成为一个严重的负担,所以你应该考虑使用更高级别的抽象,比如声明性服务(如另一个答案所建议的那样)。ServiceTracket建议不要在start方法中使用waitForService()(“强烈建议在调用BundleActivator方法期间不要使用waitForService。BundleActivator方法预计将在短时间内完成。”)。在这种情况下,有什么更好的方法来获取对该服务的引用?也许在Activator类中保存对bundlecontext的引用,然后从bundle代码本身调用ServiceTracker.getService()?如果您需要从您的bundle访问

bundlecontext
,您确实应该以某种方式从
Activator
保存它,然后使用它来获取您的服务。我还鼓励您查看一些使用此功能的系统,例如OSGi规范中的声明性服务,iPojo或Apache Felix依赖关系管理器。我尝试了waitForService,现在捆绑包挂起启动,它挂起整个引导,所以我认为waitForService不是一个好主意…我们使用Equinox作为框架,Guice/Peaberry用于DI,但Guice/Peaberry已经完成了此服务的绑定,我现在只需要将其作为客户端使用。如果不从新线程使用waitForService,它肯定会挂起。如果您已经有了DI解决方案,为什么不从您的客户机包中使用它呢?我正在尝试在OSGI中部署两个包,但只有一个包变为活动的,无论是哪个先部署的。我无法访问第二个捆绑包中的服务。有什么解决办法吗?