OSGi中的服务引用

8

当从bundle context检索到OSGi服务的实例时,如果服务停止,它是否会失效?

我的初步测试表明,即使服务bundle停止,服务实例仍然可以使用,这与我对OSGi动态特性的理解相矛盾。

我想这归结于从OSGi容器中的另一个bundle(通过ServiceTracker)检索服务实际上是做了什么,它是创建一个新实例还是给你一个指向在容器中注册的实例的指针?

在服务停止后继续使用服务实例是否存在任何危险?

6个回答

5
这是一个非常好的问题,因此我深入研究了规范以寻找确定的答案。事实证明,有一整个章节讨论了这个问题 - 请参见OSGi Service Platform Core Specification, Release 4, Version 4.2第132页开始的5.4过期引用部分。
根据规范回答您的问题:
未注册的服务的行为是不确定的。这样的服务可能会继续正常工作或自行抛出异常。
为防止潜在问题:
Bundle必须侦听Framework生成的事件,以清理和删除过期引用。
规范还提供了一些如何最小化过期引用后果的提示。

谢谢你的回答,不幸的是并不是我所希望的明确的肯定或否定! - James Carr

2
您说得对,这与OSGi的动态特性是矛盾的。我认为并没有保证服务将可用,尽管不同的OSGi容器和服务实现本身可能会有所不同。
例如,如果服务是使用Spring DM创建并注册的,则检索到的服务实际上是基于Spring的代理,指向底层实现,而实现仍然可能消失。因此,直接引用实现的服务引用可能会阻止该对象被删除,而基于代理的引用则不会。

1

OSGi规范说明:

Bundle是在正常应用程序编程中可见的实体。例如,当一个Bundle被停止时,它的所有服务都将被注销。

因此,您不应该能够从已停止的Bundle中获取服务。但从技术上讲,可能可以使用它,至少只要您持有对服务对象的引用(没有人可以从您那里拿走它,并且它不会被GC'd)。但我认为使用该服务并不安全。它可能取决于其他Bundle资源,在Bundle停止后不可用。


1
当从bundle context检索到OSGi服务的实例时,当服务停止时,它是否会失效?
不会,引用本身不会失效。只要容器内的某些内容持有它,它也不能被GC回收。
然而,它是否仍然有用,取决于服务实现本身,而不是容器。
我的初步测试表明,即使在服务bundle停止后,服务实例仍然可以使用,这与我对OSGi动态性质的理解相矛盾。
规范本身指出不应该保留这样的引用,但实现者需要正确地实现规范;这意味着没有矛盾,只有一个事实,即您可以实现和部署不按照规范正确行为的bundles。
我想这归结于从OSGi容器中的另一个bundle(通过ServiceTracker)检索服务实际上是做什么,它是创建一个新实例还是给您一个指向在容器中注册的实例的指针?

容器不会创建服务的新实例,除非涉及到ServiceFactory(请参见规范)。查找服务应始终为您提供指向容器中已注册实例的指针。

在服务停止后使用服务实例是否存在任何危险?

这完全取决于服务实现方式;但是,在一个Bundle中这样做会自动创建一个与规范不符合的Bundle。

在实践中,许多服务都被实现为释放资源和引用,并且不再正确响应。


0

一个服务引用不应该被保留为引用。您应该始终在运行时查找服务。然而,这将使您与OSGI api联系在一起,而这并不总是想要的。

请看一下以下内容: - OSGI serviceTracker - OSGI declarative services - OSGI BluePrint - Spring DM - Peaberry - iPojo

它们都会为您处理动态性,其中大多数没有使用OSGI api。

此致敬礼,

Leen Toelen


0
关于您的问题,即在服务停止后使用服务实例是否危险。引用4.2核心规范(5.4过时引用)中的内容:
“注销的服务的行为是未定义的。这些服务可能会继续正常工作或自行抛出异常。”
我不想在此引用规范的整个部分,但以下句子是关于使用过时引用的危险的良好讨论:
“过时引用是指引用属于已停止的包的类加载器或与已注销的服务对象相关联的Java对象的引用。标准Java不提供任何通用方法来清除过时引用,包开发人员必须仔细分析其代码以确保删除过时引用。”
“过时引用可能会对Java垃圾收集器从回收已停止的包的类和可能的实例造成阻碍。这可能导致内存使用量显着增加,并可能导致更新本地代码库失败。强烈建议使用服务跟踪器或声明式服务的包使用服务。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接