OSGi:Import-Package/Export-Package与Require-Capability/Provide Capability有什么区别?

14

我目前正在使用OSGi框架,但是有一些概念对我来说不是完全清晰。我已经自己搜索过了,但找不到一个清晰解释的答案。

在Bundle的清单标头中,会使用两个标头Import-PackageExport-Package。名称说明了一切:对特定包的需求和提供特定包。为了获得该包(或提供该包),必须在需要 Import 的框架中安装完整的Bundle。

但是,我们来到了Requirements-Capabilities模型的部分。这实际上可以做到与Import-PackageExport-Package标头相同的事情。这个Requirements-Capability模型也有相关的标头:Require-CapabilityProvide-Capability。同样,它们代表着需要某物和提供某物。

我知道Requirements-Capability模型是在OSGi规范的开发后期才引入的。但是无法确定是在哪一年和版本中提出的。

但是,

  • 为什么要将其添加到规范中呢?我看不出它比Import/Export-package提供了更多的东西:创建对其他包/Bundle的依赖关系?

  • 能否有人让我更好地了解这两组概念之间的差异(优缺点)?

2个回答

19
1998年,我们开始使用OSGi,有一些明确的要求,但当然没有清晰的预见。因此,我们开始明确地对我们拥有的要求和能力进行建模:包。Import-Package需要一种能力,而这种能力是由Export-Package提供的。
2003年,Eclipse想要开始使用OSGi,但他们需要一个工具来要求另一个bundle,他们不喜欢导出和导入所有的包的想法。实际上,在那个时候,他们未能看到包的好处。为了满足他们,我们添加了Require-Bundle和Fragment-Host(他们的另一个愿望,结果并不是很好)。
在我们指定了带有这些扩展的OSGi 4.x之后,我们开始思考一个存储库,Richard开发了Oscar Bundle Repository。分析OSGi 4.0中新标头的情况,Import-Package的实现看起来很像Require-Bundle,甚至类似于Fragment-Host处理。
2006年,Richard S. Hall和我撰写了RFC 112,提出了一个更通用的模型,捕捉现有依赖模型的语义,但不针对每种需求进行特定的处理。也就是说,对于Framework解析器,Import-Package和Require-Bundle仅在其命名空间上有所不同。将Import-Package视为通用需求,将Export-Package视为通用能力,使存储库模型变得极为简单。更好的是,它是可扩展的,因为我们始终可以添加更多的命名空间。这使得解析器完全独立于实际使用的命名空间。
经过一番激烈的讨论,OSGi核心平台专家组决定接受基本想法并制定了需求和能力规范。虽然这最初是用于存储库的模型,但事实证明它对框架本身非常有用。因此,我们决定将现有规范适应于此模型。OSGi 4.3在内部将Import-Package、Export-Package、Require-Bundle等视为资源(bundle)的要求和能力。为了向后兼容,我们保留了现有头文件,但它们在内部被转换为要求和能力。
然后最终回答您的问题。随着时间的推移,OSGi规范添加了越来越多的命名空间。命名空间类似于要求和能力的类型。它定义了该命名空间中一组能力属性的语义。要求是对这些属性断言的过滤器表达式。资源具有一组能力,当它的所有要求都得到满足时,这些能力提供给运行时。解析器的任务是找到一组资源,这些资源都互相满足,并满足运行时提供的能力。
例如,我们添加了osgi.ee命名空间来精确定义bundle可以在哪些VM上运行。我们添加了osgi.extender命名空间来模拟对外部程序(如服务组件运行时(SCR))的依赖关系。大多数SCR组件不需要来自SCR本身的任何包,我们努力使它们尽可能独立。但是,除非运行时中的某个bundle提供SCR功能,否则SCR组件将无用。请注意,这不能使用Require-Bundle,因为SCR有多个实现。我认为有大约20个命名空间。每个命名空间都在一个Namespace类中定义。
这个模型给OSGi带来了许多优势:
- 内聚性 虽然规范添加了许多命名空间,但解析器实现从未改变,因为它们适用于通用模型。 - 细粒度 OSGi bundles在描述它们的依赖关系方面是独特的,以非常细粒度的方式进行描述。我所知道的所有模块系统都倾向于使用简单的模块到模块的依赖关系,而这种依赖关系不允许替换。 - 灵活性 由于框架将bundles之间的依赖关系具体化,因此在运行时可以利用这些依赖关系。例如,在OSGi enRoute中,我通过遍历这些运行时连线将bundle链接到其网页。
我个人认为,OSGi的要求和能力模型是它最好保守的秘密之一。就我所见,它可以在许多领域中使用,以将许多开发项目改进为软件工程领域的一部分。
这个问题唯一令人失望的部分是我认为我们在核心规范中已经相当好地描述了这一点。 :-)

1
谢谢您为我澄清这个问题。这正是我需要完全理解整个大局的东西。我一直在阅读核心规范的部分,但是信息量很大,有点失去了一个好的概述。非常感谢! - BramCoding
关于您的失望:OSGi规范的一个重大缺陷是缺乏这种背景信息,提供有关意图、机制关系以及历史发展等方面的深入洞察。易于阅读的规范的积极例子有很多,例如IETF RFCs中的这个。简介非正式部分为读者提供了背景知识和示例,以便轻松理解正式部分。要掌握OSGi,您只能通过像这样的贡献获得此类信息。 - Michael Lipp
我认为这是一个不公平的指责,因为这篇文章中提到的几乎所有内容都在我链接的OSGi中,包括大量详细的图片。所有的OSGi规范都以背景信息开始。然而,当我们编写它时,经常被指责规范太复杂了,因为有太多的页面……这些东西之所以复杂,是因为它们不像熟悉的技术,而不是因为文档不完善或具有某种固有的复杂性。 - Peter Kriens

7
需求和能力模型是Import/Export包模型的扩展。实际上,您可以将包导入表示为需求,将包导出表示为能力。
导出/导入包允许松散耦合。您可以导出API,客户端导入它。这样,客户端只需要知道API,因此实现了松散耦合。
在以后的阶段,当您从捆绑包中组装应用程序时,这种松散耦合使自动化过程变得困难。
如果您只向解析器提供客户端捆绑包,则它只能自动查找您需要提供API的捆绑包。如果API的实现位于不同的捆绑包中,则解析器无法知道您需要它。
这就是需求可以帮助的地方。让我们以HTTP白板模型为例。要发布servlet的捆绑包需要导入servlet api包,但还需要表达它想要osgi http白板的实现。
这可以通过具有namespace="osgi.implementation"、name="osgi.http"、version="1.1.0"的要求来表达。由于手动编写困难,因此提供了注释支持。
@HttpWhiteboardServletPattern("/myservlet")
@Component(service = Servlet.class)
public class MyServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws IOException {
        resp.getWriter().println("Hello");
    }
}

注释@HttpWhiteboardServletPattern间接地转换为上述要求。
因此,当您使用此类构建一个bundle时,它将导入servlet api包,并且还需要http whiteboard实现的要求。
现在,如果您查看像felix http服务这样的实现bundle,您将看到它提供了whiteboard impl的功能。
因此,如果您有一个包含您的bundle、servlet API和felix http服务的OSGi存储库,那么只需向解析器提供您的bundle,它就可以为您提供完整的应用程序。

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