4

在中使用 OSGi 的最佳实践是ServiceTracker什么BundleActivator?我在网上看到过在start方法中打开跟踪器的示例,将其存储在实例变量中,然后在stop方法中关闭它,在包的生命周期内保持打开状态。这合适吗?我一直在编写代码,在需要时打开跟踪器,获取服务并使用它,然后关闭跟踪器。当然,BundleContext如果我想在以后使用它,这需要将其本身存储在一个实例变量中。由于我必须存储一个或另一个,因此存储哪个可能没有太大区别。

在一个相关的问题中,如果我每次需要时都打开跟踪器,是否有必要在使用从它获得的服务时保持打开,或者我可以打开跟踪器,获取服务,关闭跟踪器,然后使用该服务?我认为没有理由在使用该服务之前无法关闭跟踪器。

4

4 回答 4

7

服务来来去去——作为 OSGi 开发人员,您的职责是仅在服务包发布时使用服务,更重要的是在服务未发布时发布服务。如果您在取消发布后继续使用服务,则可能会发生不可预知的错误。至少,您将导致与该服务实例关联的堆空间被固定在内存中,这会破坏 OSGi 动态安装和卸载包的能力。

所以,你问是否应该在使用服务之前关闭 ServiceTracker:我的回答是NO。ServiceTracker 充当指向当前服务的“智能指针”,它管理所有侦听器等,以便在服务消失时得到通知。如果您关闭跟踪器,那么您将不再了解服务的状态,那么您如何知道它是否仍然有效?

使用 ServiceTracker 的理想模式——假设跟踪器始终保持打开状态——如下:

{    
    Service svc = tracker.getService();
    svc.doSomething();
}
// 'svc' is now forgotten, and may be garbage collected

也就是说,当您调用getService()跟踪器时,您会获得一个实际服务的实例,但您应该快速使用它,然后尽快忘记它。您绝对不能将结果存储getService()在字段中并长时间保存。

至于您是否应该仅在需要时打开和立即关闭跟踪器——不,绝对没有必要这样做。一个开放的跟踪器不会消耗任何重要的资源,它只是意味着它被注册为一个监听器,以便它知道服务何时来去。事实上,重复打开和关闭跟踪器效率很低,因为每次打开它时,它都必须与服务注册表的当前状态同步。这就是为什么您在示例中看到的模式通常是在捆绑激活期间打开跟踪器并保持打开状态......这是最好的模式。

顺便说一句,也不需要在您的BundleActivator.stop方法中显式关闭跟踪器。当您的捆绑包停止时,与您的跟踪器关联的所有资源都将自动清理。明确关闭的唯一原因是如果您有多个跟踪器和/或服务注册,并且您希望控制清理的顺序。

现在说了以上所有,我要扔手榴弹:请停止使用ServiceTracker这是一个非常低级的实用程序,很少需要,然后只在“管道”或基础设施代码中。您的大多数应用程序都应该使用更高级别的抽象来构建。我强烈建议使用声明式服务,这比使用 ServiceTrackers 容易得多。

于 2013-08-30T00:23:33.297 回答
5

Service Tracker 的最佳实践是使用声明式服务。

对于专家:在一些高度专业化的情况下,Service Tracker 很有用(而且不容错过!),但如果您必须提出这个问题,那么 Service Tracker 不适合您。Service Tracker 是一种非常底层的方式来处理中间件使用的服务,例如声明式服务实现、蓝图实现等。

于 2013-08-30T07:32:20.363 回答
2

如果您只想为服务呼叫打开跟踪器,则根本不需要跟踪器。您所要做的就是通过 bundleContext 获取服务,并在完成后取消获取它。

ServiceTracker 不仅适用于调用服务,而且您还可以调用 waitForService 方法,这样您的线程将等待,直到一个好的服务可用。

如果您使用服务跟踪器并且每次调用 getService() 来获取服务对象,您可能不会调用相同的服务。Service Tracker 默认跟踪每一项满足过滤条件的服务,因此如果您上次使用的服务未注册,下次将向您提供另一项服务。

如果您从服务跟踪器继承或编写 ServiceTrackerCustomizer,您可以捕获服务跟踪事件。例如,您可以创建一个逻辑,在每次注册满足您要求的服务时提供自己的服务对象。您还可以指定应跟踪哪些服务(您在addingService 中返回null,而不是跟踪该服务)。

简而言之:

  • 如果您只想调用一次或两次服务(例如,当您的包启动或停止时),您可以简单地通过上下文获取服务并取消它
  • 如果您想在捆绑包处于活动状态时多次调用服务,或者您想根据服务可用性事件创建自定义逻辑,请使用服务跟踪器

如果您选择第一个选项,永远不要在成员变量中长时间保留服务对象!如果是第一个选项,您应该在不再需要该服务时立即取消该服务。服务跟踪器也是如此。每次调用 getService 方法,而不是将其保存在类的成员变量中,因为它可能在您再次需要它时被取消注册。

其他 OSGi 专家在 stackoverflow (设计 OSGi 的人),所以他们可能会给出更具体的答案。

于 2013-08-29T22:23:20.703 回答
0

我认为ServiceTracker对于在方法BundleActivator.start()内部activate()Components.

在初始化时使用它们的目标是避免在我们也在初始化的捆绑包中使用服务时可能导致的死锁。

是推荐ServiceTrackers的情况,还是有其他更好的基于 DS 的初始化时间模式?

于 2015-08-05T09:29:20.800 回答