ServiceTracker找不到现有服务

时间:2011-03-20 20:00:22

标签: osgi

我正在使用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不能 我的包发现(即为NULL),即使这样 我的捆绑包状态为ACTIVE。
  • 如果我停止/启动我的捆绑MyService 可以找到并再次使用。

我认为问题不在于托管MyService的捆绑包,因为它显然存在,如果我的捆绑包重新启动,可以再次找到它。

看起来我的bundle在拥有依赖服务的bundle之前加载,这就是为什么它在重启后无法找到它并且在我重新启动bundle之后可以找到它。

如果我使用

列出可用服务,则表明这一点
ServiceReference[] ref = tracker.getServiceReferences();

它在OSGi重新启动后没有找到任何服务,但是在我停止/启动查找它的bundle后它确实找到了MyService。

我试图将Require-Bundle引用设置为托管MyService的bundle,希望OSGi框架能够识别依赖,但它没有帮助。

任何想法......?

3 个答案:

答案 0 :(得分:4)

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

现在,如果您想跟踪和使用该服务,我会生成一个新线程来执行此操作,并使用waitForService代替getService

答案 1 :(得分:2)

使用ServiceTracker做正确的事情。但问题是期望服务器是跟踪器在激活器中可用。您不希望在启动捆绑包和注册服务的捆绑包之间建立排序约束。除非你真的需要在激活器的启动方法中使用该服务(并且你可能不应该),否则只需在实际需要时获得服务。

另一个想法是考虑使用Declarative Services来管理您的服务依赖项。

答案 2 :(得分:1)

OSGi中的服务非常不稳定,所以你永远不要指望一个人在你需要的时候就在那里,或者在你得到它之后留在那里。这就是为什么你的捆绑包应该让自己异步通知服务。

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以获取更多信息。

管理这个很快就会成为一个严重的负担,所以你应该考虑使用更高级别的抽象,比如声明性服务(正如另一个答案所建议的那样)。