【问题标题】:When should I use Import-Package and when should I use Require-Bundle?什么时候应该使用 Import-Package,什么时候应该使用 Require-Bundle?
【发布时间】:2010-12-24 08:41:25
【问题描述】:

OSGi 允许通过 Import-Package 确定依赖关系,它只连接单个包(从任何捆绑包中导出)和Require-Bundle,它连接到特定命名包的导出。

在构建一个全新的 OSGi 应用程序时,我应该使用哪种方法来表示依赖关系?大多数捆绑包将是内部的,但会有一些依赖于外部(开源)捆绑包。

【问题讨论】:

  • 来自eclipsesource.com/blogs/2009/07/14/…:“看,Require-Bundle 已经在 Eclipse 中使用了一段时间,主要是出于遗留原因。我们不再推荐使用它。如果您希望捆绑包之间的耦合更松散,则 Import-Package 会更好。但是,请注意拆分包可能导致的痛苦。”

标签: osgi


【解决方案1】:

我相信 Import-Package 为您提供了更松散的耦合,应该是首选。我在声明对我不拥有的包的依赖项时使用它,例如 slf4j,我可以根据需要交换实现。当依赖项是我可以控制的,例如我自己的包时,我会使用 Require-Bundle,因为无论如何任何重要的更改都会由我自己完成。

【讨论】:

    【解决方案2】:

    我相信Require-Bundle 是一个 Eclipse 的东西(现在它已经在 OSGi 规范中以适应 Eclipse)。 “纯”OSGi 方式是使用Import-Package,因为它专门将包与提供它的包分离。您应该声明对您需要的功能(某个包的某个版本提供的 Java API)的依赖关系,而不是该功能的来源(这对您来说无关紧要)。这使捆绑包的组合更加灵活。

    JavaScript 类比:这就像检测 Web 浏览器是否支持某个 API,而不是从用户代理字符串中推断出它是哪种浏览器。

    OSGi 联盟的 Peter Kriens 在OSGi blog 上对此有更多的看法。

    可能需要使用Require-Bundle 的唯一情况是,如果您有拆分包,即分布在多个捆绑包中的包。当然不鼓励拆分包。

    【讨论】:

    • Require-Bundle 和 Import-Package 都在 OSGi 规范中定义;两者没有“纯”变体。
    • @AlBlue:更新了我的答案,以更清楚地说明,虽然 Require-Bundle 在规范中,但它只是为了与 Eclipse 兼容。
    • 我认为蒂洛是对的。正如 Peter Kriens 在文章中提到的:“Require-Bundle 具有难以否认的直观吸引力。”但它不必要地将捆绑在一起。在 Java 世界中,我会将其与 IoC 与直接查找依赖项进行比较。一个例子是依赖于commons-logging 包与依赖于commons-logging API 包。在后一种情况下,您可以轻松地将common-logging 捆绑包与适当的 SLF4J 适配器捆绑包交换,该捆绑包还导出commons-logging API 包,从而无缝创建从commons-logging 到 SLF4J 的桥梁。
    • +1 因为这是对这个主题的一个很好的讨论。小补充:require-bundle 可用于表达与包不同的依赖关系,例如一个 Bundle 需要以另一个 bundle 形式存在的资源。
    • 只是为了观察一下——“要求捆绑包已符合 OSGi 规范以适应 Eclipse”实际上是不正确的。它是在 OSGi 4 中添加的,但大部分是 Eclipse Import-Package。 Eclipse 3.0 于 2004 年 6 月转而使用 OSGi; OSGi 4(带有 Require-Bundle)于 2005 年 8 月发布。
    【解决方案3】:

    我不相信使用 Import-Package 会更好,因为我在使用捆绑包时的默认期望是使用关联的公共 API。因此,Require-Bundle 更有意义。

    【讨论】:

    • 这种说法毫无意义。您的理由是您使用 Import Package 而不是 Require-Bundle 的原因。处理公共 API,不用担心谁提供它。您不使用捆绑包,而是使用 API。
    【解决方案4】:

    优先使用导入包而不是 Require-Bundle。

    需要捆绑包:

    • 指定要使用的显式捆绑包(和版本)。如果需要重构需求包并将包移至其他地方,则依赖项将需要更改其 MANIFEST.MF
    • 让您可以访问捆绑包的所有导出,无论它们是什么,也无论您是否需要它们。如果您不需要的部分有自己的依赖项,您将需要这些部分
    • 可以重新导出捆绑包
    • 虽然不鼓励,但允许使用拆分包,即:分散在多个包中的包
    • 可用于非代码依赖,例如:资源、帮助等

    进口包装:

    • 松耦合,只指定包(和版本),运行时找到所需的包
    • 可以换出实际的实现
    • 包所有者可以将依赖包移动到不同的包中
    • 但需要在较低粒度级别维护更多元数据(即每个包名称)

    【讨论】:

    • 对于 Import-Package,如果您需要特定版本的包但捆绑包中实际上包含该版本怎么办? AFAIK,java 包没有版本。
    【解决方案5】:

    Import-Package 应该更好,因为如前所述,您可以将一个包从一个包移动到另一个包,而无需更改现有客户端的 MANIFEST.MF

    但是……

    如果您使用 Eclipse 开发您的捆绑软件,那么使用 Require-Bundle 是有实际理由的:

    Eclipse 不使用包作为分辨率单位。它使用捆绑包。也就是说,如果您使用一个包中的一个包,Eclipse 会编译您的包,而不会报告使用未从该包中导入的其余包的任何问题。

    您可以(您是人类)认为一切正常并上传您的捆绑包进行部署,但是......您的捆绑包会在运行时中断。

    我很确定,因为这个问题今天(对我来说!)发生了。

    最好的解决方案是更改 Eclipse 类路径容器,但是...如果不这样做...您可以决定避免这种需要捆绑包而不是包的问题,​​支付上述价格(包之间没有向后兼容的代码移动)。

    【讨论】:

      【解决方案6】:

      避免导入包。 由于包提供了包之间的多对多关系,因此它们容易出现难以检测和避免的依赖循环。

      另一方面,Require-Bundle 引用单个包,通过微不足道的构建时检查使依赖关系图免受循环影响。 使用 Require-Bundle 可以更轻松地构建具有隔离的较低抽象级别的分层架构。

      【讨论】:

        猜你喜欢
        • 2012-03-19
        • 2023-04-02
        • 2011-04-15
        • 2017-04-10
        • 2018-05-12
        • 2018-12-11
        • 1970-01-01
        • 2022-09-28
        • 2021-09-07
        相关资源
        最近更新 更多