我应该打开OSGi ServiceTracker,还是在使用后关闭它?

时间:2013-08-29 21:37:20

标签: java osgi apache-felix

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

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

4 个答案:

答案 0 :(得分:5)

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

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

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

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

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

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

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

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

答案 1 :(得分:5)

服务跟踪器的最佳实践是使用声明性服务。

对于专家:有一些高度专业化的案例,其中服务跟踪器是有用的(并且是不可错过的!)但是如果您不得不提出这个问题,那么服务跟踪器不适合您。服务跟踪器是一种非常低级的方式来处理中间件使用的服务,如声明式服务实现,蓝图实现等。

答案 2 :(得分:2)

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

ServiceTracker不仅有助于调用服务,还可以调用waitForService方法,因此您的线程将等待,直到有良好的服务可用。

如果您使用服务跟踪器,并且每次您不能调用相同的服务时调用getService()来获取服务对象。默认情况下,Service Tracker会跟踪符合过滤条件的所有服务,因此,如果您上次使用的服务在下次向您提供其他服务时未注册。

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

简而言之:

  • 如果您只想调用一次或两次服务(例如当您的软件包启动或停止时),您只需通过上下文获取服务并取消注册即可
  • 如果您想在捆绑包处于活动状态期间多次呼叫服务,或者您希望根据服务可用性事件创建自定义逻辑,请使用服务跟踪器

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

其他OSGi专家来自stackoverflow(设计OSGi的人),以便他们提供更具体的答案。

答案 3 :(得分:0)

我认为 ServiceTracker 对于在方法BundleActivator.start()内和activate()方法Components内使用服务非常有用。

在初始化时使用它们的目的是避免在我们在正在初始化的bundle使用Services时可能导致的死锁。

是否建议使用 ServiceTrackers 或是否有基于DS的其他更好的模式用于初始化时间?