服务来来去去——作为 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 容易得多。