在ServiceTracker
中使用OSGi BundleActivator
的最佳做法是什么?我在Web上看到了在start
方法中打开跟踪器的示例,将其存储在实例变量中,并在stop
方法中关闭它,使其在捆绑的生命周期中保持打开状态。这个合适吗?我一直在编写代码,只要我需要它就打开跟踪器,获取服务并使用它,然后关闭跟踪器。当然,如果我想在以后使用它,则需要将BundleContext
本身存储在实例变量中。因为我必须存储一个或另一个,所以我存储的可能没有多大区别。
在一个相关的问题中,如果我每次需要时都打开跟踪器,是否有必要在我使用我从中获得的服务时保持打开状态,或者我可以打开跟踪器,获取服务,关闭跟踪器,然后使用该服务?在使用该服务之前,我认为没有理由不能关闭跟踪器。
服务来来去去 - 作为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更容易。
服务跟踪器的最佳实践是使用声明性服务。
对于专家:有一些高度专业化的案例,其中服务跟踪器是有用的(并且是不可错过的!)但是如果您不得不提出这个问题,那么服务跟踪器不适合您。服务跟踪器是一种非常低级的方式来处理中间件使用的服务,如声明服务实现,蓝图实现等。
如果您只想打开一个服务电话跟踪器,您根本不需要跟踪器。您所要做的就是通过bundleContext获取服务,并在完成后取消注意。
ServiceTracker不仅适用于调用服务,还可以调用waitForService方法,因此您的线程将一直等到有良好的服务可用。
如果您使用服务跟踪器,并且每次您不能调用相同的服务时调用getService()来获取服务对象。默认情况下,Service Tracker会跟踪符合过滤条件的所有服务,因此,如果您上次使用的服务在下次向您提供其他服务时未注册。
如果您从服务跟踪器继承或编写ServiceTrackerCustomizer,则可以捕获服务跟踪事件。例如。您可以创建一个逻辑,每次注册满足您要求的服务时,您都会提供自己的服务对象。您还可以指定应跟踪哪些服务(在添加Service时返回null,而不会跟踪该服务)。
简而言之:
如果选择第一个选项,则永远不要在成员变量中保留服务对象更长的时间!如果是第一个选项,您应该在不再需要服务时立即取消服务。服务跟踪器也是如此。每次调用getService方法而不是将其保存在类的成员变量中,因为它可能在您需要它时再次注册。
其他OSGi专家来自stackoverflow(设计OSGi的人),因此他们可能会提供更具体的答案。
我认为ServiceTracker对于在BundleActivator.start()
方法内部和activate()
方法Components
中使用Services非常有用。
在初始化时使用它们的目的是避免在我们在正在初始化的bundle使用Services时可能导致的死锁。
是建议使用ServiceTrackers还是基于DS进行初始化时间的其他更好的模式?