ServiceTracker 找不到现有服务

发布于 2024-10-23 17:39:57 字数 953 浏览 2 评论 0原文

我使用 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),尽管如此 我的捆绑包处于“活动”状态。
  • 如果我停止/启动我的捆绑包 MyService 可以被找到并再次使用。

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

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

一个迹象是,如果我列出可用的服务,

ServiceReference[] ref = tracker.getServiceReferences();

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

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

有什么想法吗...?

I am using ServiceTracker in order to located registered services in our OSGi environment.
I have got this code in the Bundle Activator start method:

    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");
    }

The problem is this:

  • If I install and start my bundle the
    service can be found and used.
  • If I restart OSGi completely MyService cannot be
    found by my bundle (i.e. is NULL) even though that
    my bundle is on status ACTIVE.
  • If I stop/start my bundle MyService
    can be found and used again.

I don't think the problem lies in the bundle that hosts MyService since it is clearly there and can be found again if my bundle is restarted.

It looks like my bundle loads before the one that has the dependent service in it which is why it can't find it after a restart and can find it after I restart my bundle.

An indication to that is that if I list available services using

ServiceReference[] ref = tracker.getServiceReferences();

it finds no services after the OSGi restart but it does find MyService after I stop/start my bundle that looks for it.

I was trying to set Require-Bundle reference to the bundle that hosts MyService hoping that the OSGi framework will recognize the dependency but it didn't help.

Any ideas...?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

触ぅ动初心 2024-10-30 17:39:57

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

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

If you use the ServiceTracker from the BundleActivator, you effectively freeze the entire framework (so, no other bundles can be started at the same time). If the bundle that provides your service starts after the bundle with the tracker, you will not see the service. This explains why stopping and starting your bundle later on gives you your service.

Now, if you want to track and use the service, I would spawn a new thread to do that, and use waitForService in stead of getService.

猫性小仙女 2024-10-30 17:39:57

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

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

You are doing the right thing by using a ServiceTracker. But the problem is expecting the service being tracker to be available in the activator. You do not want to establish an ordering constraint between starting your bundle and the bundle registering the service. Unless you really need to use the service in the activator's start method (and you probably shouldn't), just get the service later when you actually need.

Another idea is to consider using Declarative Services to manage your service dependencies.

书信已泛黄 2024-10-30 17:39:57

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 了解更多信息。

管理它很快就会成为一个严重的负担,因此您应该考虑使用更高级别的抽象,例如声明性服务(如另一个答案所建议的)。

Services are very volatile in OSGi, so you should never expect one to be there when you need it or stay there after you get it. That's why your bundle should let itself be notified of services asynchronously.

The ServiceTracker class accepts a ServiceTrackerCustomizer (and is one itself) that is notified when services come and go.

Most of the time, the right way to use a service tracker is as follows:

// 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);
    }
}

Note that we only track the MyService services and don't use any customizer (we pass null as third parameter to the constructor), but override the two important methods instead. Another important method is modifiedService; please read the Javadoc for more information.

Managing this can quickly become a serious burden, so you should consider using higher level abstractions like declarative services (as suggested by another answer).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文